import { useEffect, useMemo, useState } from "react";
import {
  fetchInfo,
  downloadImmediate,
  FORMAT_EXTS,
  type InfoResponse,
  parseContentDispositionFilename,
} from "../../api/apps/Downloader";

export default function Downloader() {
  const [url, setUrl] = useState("");
  const [probing, setProbing] = useState(false);
  const [downloading, setDownloading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [info, setInfo] = useState<InfoResponse | null>(null);

  const [ext, setExt] = useState<typeof FORMAT_EXTS[number]>("mp4");
  const [videoRes, setVideoRes] = useState<string | undefined>(undefined);
  const [audioRes, setAudioRes] = useState<string | undefined>(undefined);

  useEffect(() => {
    if (info?.video_resolutions?.length && !videoRes) {
      setVideoRes(info.video_resolutions[0]);
    }
    if (info?.audio_resolutions?.length && !audioRes) {
      setAudioRes(info.audio_resolutions[0]);
    }
  }, [info]);

  async function onProbe(e: React.FormEvent) {
    e.preventDefault();
    setError(null);
    setInfo(null);
    setProbing(true);
    try {
      const res = await fetchInfo(url);
      setInfo(res);
      // reset selections from fresh info
      setVideoRes(res.video_resolutions?.[0]);
      setAudioRes(res.audio_resolutions?.[0]);
    } catch (e: any) {
      setError(
        e?.response?.data?.error ||
        e?.response?.data?.detail ||
        e?.message ||
        "Failed to get info."
      );
    } finally {
      setProbing(false);
    }
  }

  async function onDownload() {
    setError(null);
    setDownloading(true);
    try {
      const { blob, filename } = await downloadImmediate({
        url,
        ext,
        videoResolution: videoRes,
        audioResolution: audioRes,
      });
      const name = filename || parseContentDispositionFilename("") || `download.${ext}`;
      const href = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = href;
      a.download = name;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(href);
    } catch (e: any) {
      setError(
        e?.response?.data?.error ||
        e?.response?.data?.detail ||
        e?.message ||
        "Download failed."
      );
    } finally {
      setDownloading(false);
    }
  }

  const canDownload = useMemo(
    () => !!url && !!ext && !!videoRes && !!audioRes,
    [url, ext, videoRes, audioRes]
  );

  return (
    <div className="max-w-3xl mx-auto p-4 space-y-4">
      <h1 className="text-2xl font-semibold">Downloader</h1>

      {error && <div className="rounded border border-red-300 bg-red-50 text-red-700 p-2">{error}</div>}

      <form onSubmit={onProbe} className="grid gap-3">
        <label className="grid gap-1">
          <span className="text-sm font-medium">URL</span>
          <input
            type="url"
            required
            placeholder="https://example.com/video"
            value={url}
            onChange={(e) => setUrl(e.target.value)}
            className="w-full border rounded p-2"
          />
        </label>

        <div className="flex gap-2">
          <button
            type="submit"
            disabled={!url || probing}
            className="px-3 py-2 rounded bg-brand-accent text-brand-text disabled:opacity-50"
          >
            {probing ? "Probing..." : "Get info"}
          </button>
          <button
            type="button"
            onClick={onDownload}
            disabled={!canDownload || downloading}
            className="px-3 py-2 rounded bg-brand-accent text-brand-text disabled:opacity-50"
          >
            {downloading ? "Downloading..." : "Download"}
          </button>
        </div>
      </form>

      {info && (
        <div className="space-y-3">
          <div className="flex items-start gap-3">
            {info.thumbnail && (
              <img
                src={info.thumbnail}
                alt={info.title || "thumbnail"}
                className="w-40 h-24 object-cover rounded border"
              />
            )}
            <div className="text-sm text-brand-text/90 space-y-1">
              <div>
                <span className="font-medium">Title:</span> {info.title || "-"}
              </div>
              <div>
                <span className="font-medium">Duration:</span>{" "}
                {info.duration ? `${Math.round(info.duration)} s` : "-"}
              </div>
            </div>
          </div>

          <div className="grid md:grid-cols-3 gap-3">
            <label className="grid gap-1">
              <span className="text-sm font-medium">Container</span>
              <select
                value={ext}
                onChange={(e) => setExt(e.target.value as any)}
                className="border rounded p-2"
              >
                {FORMAT_EXTS.map((x) => (
                  <option key={x} value={x}>
                    {x.toUpperCase()}
                  </option>
                ))}
              </select>
            </label>

            <label className="grid gap-1">
              <span className="text-sm font-medium">Video resolution</span>
              <select
                value={videoRes || ""}
                onChange={(e) => setVideoRes(e.target.value || undefined)}
                className="border rounded p-2"
              >
                {info.video_resolutions?.length ? (
                  info.video_resolutions.map((r) => (
                    <option key={r} value={r}>
                      {r}
                    </option>
                  ))
                ) : (
                  <option value="">-</option>
                )}
              </select>
            </label>

            <label className="grid gap-1">
              <span className="text-sm font-medium">Audio bitrate</span>
              <select
                value={audioRes || ""}
                onChange={(e) => setAudioRes(e.target.value || undefined)}
                className="border rounded p-2"
              >
                {info.audio_resolutions?.length ? (
                  info.audio_resolutions.map((r) => (
                    <option key={r} value={r}>
                      {r}
                    </option>
                  ))
                ) : (
                  <option value="">-</option>
                )}
              </select>
            </label>
          </div>
        </div>
      )}
    </div>
  );
}