import { useEffect, useRef, useState } from "react";
import { Download, Film, Loader2, X, Check, Captions, FileCode, AlertTriangle, RotateCcw } from "lucide-react";
import { useStore, selectStats } from "../store";
import { useShallow } from "zustand/react/shallow";
import { msToFrame } from "../lib/time";
import { captionLinesFor, toSRT, toVTT, downloadFile } from "../lib/export-formats";

const RANGES = [
  { label: "First 10s", ms: 10_000 },
  { label: "First 30s", ms: 30_000 },
  { label: "Full video", ms: Infinity },
];

// map raw server job states → friendly, non-leaky labels (no "headless Chrome" / internal verbs)
const STATUS_LABEL: Record<string, string> = {
  starting: "Preparing…", queued: "Queued…", bundling: "Preparing…",
  rendering: "Rendering your video…", stitching: "Finishing up…", encoding: "Finishing up…",
};
const statusLabel = (s: string, ready: boolean) => (ready ? "Render complete" : STATUS_LABEL[s] || "Rendering your video…");

export function ExportModal({ open, onClose }: { open: boolean; onClose: () => void }) {
  const edl = useStore((s) => s.edl);
  const wordsById = useStore((s) => s.wordsById);
  const motion = useStore((s) => s.motion);
  const videos = useStore((s) => s.videos);
  const tracks = useStore((s) => s.tracks);
  const audioSrc = useStore((s) => s.audioSrc);
  const music = useStore((s) => s.music);
  const musicVolume = useStore((s) => s.musicVolume);
  const musicFadeInMs = useStore((s) => s.musicFadeInMs);
  const musicFadeOutMs = useStore((s) => s.musicFadeOutMs);
  const sfxStyle = useStore((s) => s.sfxStyle);
  const captionsOn = useStore((s) => s.captionsOn);
  const captionStyle = useStore((s) => s.captionStyle);
  const captionColors = useStore((s) => s.captionColors);
  const captionAnim = useStore((s) => s.captionAnim);
  const lang = useStore((s) => s.lang);
  const stats = useStore(useShallow(selectStats));
  const [range, setRange] = useState(2); // default Full
  const [hi, setHi] = useState(false);   // 4K (scale 2) vs 1080p (scale 1)
  const [job, setJob] = useState<{ id: string; status: string; progress: number; ready: boolean; error?: string } | null>(null);
  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);

  useEffect(() => {
    if (!open) return;
    // The modal stays mounted (it just renders null when closed), so a finished/failed job from a previous
    // export would linger and reopening would show the stale "Download MP4" instead of a fresh Export form.
    // Reset a terminal job on every open so the user can always start a new export (no page refresh needed).
    setJob((j) => (j && (j.ready || j.status === "error") ? null : j));
  }, [open]);

  // stop polling if the modal unmounts mid-render (otherwise the interval leaks)
  useEffect(() => () => { if (pollRef.current) clearInterval(pollRef.current); }, []);

  if (!open) return null;
  const cap = Math.min(RANGES[range].ms, stats.durationMs);
  const seconds = Math.round(cap / 1000);
  const empty = stats.durationMs <= 0; // no transcript, motion, or video → nothing to render

  async function start() {
    const durationInFrames = Math.max(1, msToFrame(cap));
    const res = await fetch("/api/export", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ edl, wordsById, motion, videos, tracks, audioSrc: audioSrc.replace(/^\//, ""), music, musicVolume, musicFadeInMs, musicFadeOutMs, sfxStyle, durationInFrames, captionsOn, captionStyle, captionColors, captionAnim, lang, scale: hi ? 2 : 1 }),
    });
    const { jobId, error } = await res.json();
    if (error) { setJob({ id: "", status: "error", progress: 0, ready: false, error }); return; }
    setJob({ id: jobId, status: "starting", progress: 0, ready: false });
    if (pollRef.current) clearInterval(pollRef.current); // never run two pollers at once
    const poll = setInterval(async () => {
      const s = await fetch(`/api/export/status?id=${jobId}`).then((r) => r.json());
      setJob({ id: jobId, status: s.status, progress: s.progress || 0, ready: !!s.ready, error: s.error });
      if (s.ready || s.status === "error") { clearInterval(poll); pollRef.current = null; }
    }, 1200);
    pollRef.current = poll;
  }

  async function downloadFcpxml() {
    const res = await fetch("/api/export/fcpxml", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ edl, videos, motion, durationInFrames: msToFrame(stats.durationMs), audioSrc: audioSrc.replace(/^\//, "") }),
    });
    downloadFile("timeline.fcpxml", await res.text(), "application/xml");
  }

  return (
    <div className="fixed inset-0 z-50 grid place-items-center bg-black/40 p-3 sm:p-6" onClick={onClose}>
      <div className="max-h-[88vh] w-full min-w-0 max-w-[440px] overflow-y-auto rounded-xl border border-border bg-surface-raised p-4 shadow-2xl sm:p-5" onClick={(e) => e.stopPropagation()}>
        <div className="mb-4 flex items-center justify-between">
          <div className="flex items-center gap-2 text-fg"><Film size={16} className="text-primary" /><span className="font-semibold">Export video</span></div>
          <button onClick={onClose} className="rounded p-1 text-fg-muted hover:bg-white/5"><X size={16} /></button>
        </div>

        {!job && (
          <>
            <div className="eyebrow mb-2">Range</div>
            <div className="mb-4 flex gap-2">
              {RANGES.map((r, i) => (
                <button key={r.label} onClick={() => setRange(i)}
                  className={"flex-1 rounded-md border px-3 py-2 text-[13px] " + (range === i ? "border-primary bg-primary/10 text-fg" : "border-border text-fg-muted hover:border-primary/40")}>
                  {r.label}
                </button>
              ))}
            </div>
            <div className="eyebrow mb-2">Resolution</div>
            <div className="mb-4 flex gap-2">
              {[{ k: false, label: "1080p", sub: "1920×1080" }, { k: true, label: "4K UHD", sub: "3840×2160" }].map((o) => (
                <button key={o.label} onClick={() => setHi(o.k)}
                  className={"relative flex-1 rounded-md border px-3 py-2 text-left " + (hi === o.k ? "border-primary bg-primary/10 text-fg" : "border-border text-fg-muted hover:border-primary/40")}>
                  <div className="text-[13px] font-medium">{o.label}</div>
                  <div className="num text-[10px] text-fg-subtle">{o.sub}</div>
                </button>
              ))}
            </div>
            <div className="mb-4 rounded-md bg-surface px-3 py-2 text-[12px] text-fg-muted">
              {hi ? "3840×2160 (4K)" : "1920×1080"} · H.264 + AAC · ~{seconds}s · {stats.kept} words · {stats.motionCount} scene{stats.motionCount === 1 ? "" : "s"}
              {hi && <span className="block text-[11px] text-fg-subtle">4K renders ~4× the pixels — slower, larger file.</span>}
            </div>
            {empty && <div className="mb-3 rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-[12px] text-amber-300">Nothing to render yet — add transcript words, a motion-graphics scene, or a video clip first.</div>}
            <button onClick={start} disabled={empty} className="w-full rounded-md bg-primary py-2.5 text-[14px] font-semibold text-white hover:brightness-105 disabled:cursor-not-allowed disabled:opacity-40">Render MP4</button>

            <div className="mt-4 border-t border-border pt-3">
              <div className="eyebrow mb-2">Captions & interchange</div>
              <div className="grid grid-cols-3 gap-2">
                <DlBtn icon={<Captions size={14} />} label="SRT" onClick={() => downloadFile("captions.srt", toSRT(captionLinesFor(edl, wordsById)), "text/plain")} />
                <DlBtn icon={<Captions size={14} />} label="VTT" onClick={() => downloadFile("captions.vtt", toVTT(captionLinesFor(edl, wordsById)), "text/vtt")} />
                <DlBtn icon={<FileCode size={14} />} label="FCPXML" onClick={downloadFcpxml} disabled={empty} />
              </div>
              <p className="mt-2 text-[11px] text-fg-subtle">SRT/VTT subtitles from the transcript · FCPXML opens in FCP / DaVinci Resolve / Premiere (relink media if moved).</p>
            </div>
          </>
        )}

        {job && job.status !== "error" && (
          <div className="py-2">
            <div className="mb-2 flex items-center gap-2 text-[13px] text-fg">
              {job.ready ? <Check size={16} className="text-success" /> : <Loader2 size={16} className="animate-spin text-primary" />}
              {statusLabel(job.status, job.ready)}
            </div>
            <div className="mb-4 h-2 overflow-hidden rounded-full bg-white/10">
              <div className="h-full bg-primary transition-all" style={{ width: `${Math.round((job.ready ? 1 : job.progress) * 100)}%` }} />
            </div>
            {job.ready ? (
              <a href={`/api/export/file?id=${job.id}`} download className="flex w-full items-center justify-center gap-2 rounded-md bg-primary py-2.5 text-[14px] font-semibold text-white hover:brightness-105">
                <Download size={15} /> Download MP4
              </a>
            ) : (
              <p className="text-center text-[12px] text-fg-subtle">This can take a minute for longer videos — you can keep editing.</p>
            )}
          </div>
        )}

        {job?.status === "error" && (
          <div className="py-2 text-center">
            <div className="mx-auto mb-2 grid h-10 w-10 place-items-center rounded-full bg-destructive/10"><AlertTriangle size={20} className="text-destructive" /></div>
            <div className="text-[14px] font-semibold text-fg">Render didn’t finish</div>
            <p className="mx-auto mt-1 max-w-[320px] text-[12.5px] text-fg-muted">Something went wrong while rendering. Try again — if it keeps failing, contact support.</p>
            {job.error && <p className="mx-auto mt-1.5 max-w-[320px] truncate text-[11px] text-fg-subtle/70" title={job.error}>{job.error}</p>}
            <div className="mt-3 flex items-center justify-center gap-2">
              <button onClick={() => setJob(null)} className="inline-flex items-center gap-1.5 rounded-md bg-primary px-4 py-2 text-[13px] font-semibold text-white hover:brightness-105"><RotateCcw size={14} /> Try again</button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function DlBtn({ icon, label, onClick, disabled }: { icon: React.ReactNode; label: string; onClick: () => void; disabled?: boolean }) {
  return (
    <button onClick={onClick} disabled={disabled} className="flex items-center justify-center gap-1.5 rounded-md border border-border py-2 text-[12px] font-medium text-fg-muted hover:border-primary hover:text-fg disabled:cursor-not-allowed disabled:opacity-40">
      {icon} {label}
    </button>
  );
}
