// src/components/CaptionMenu.tsx — FINAL (gallery + animation picker + color overrides).
import { useState, useRef, useEffect } from "react";
import { createPortal } from "react-dom";
import { Captions, ChevronUp, Pipette, X } from "lucide-react";
import { useStore } from "../store";
import { CAPTION_STYLES, CAPTION_ANIMS, captionStyleById, resolveCaptionStyle } from "../lib/captions";

const HEX6 = /^#?[0-9a-fA-F]{6}$/;
const FALLBACK_HIGHLIGHT = "#16a34a";

type ColorKey = "active" | "base" | "highlight";

export function CaptionMenu() {
  const on = useStore((s) => s.captionsOn);
  const styleId = useStore((s) => s.captionStyle);
  const colors = useStore((s) => s.captionColors);
  const anim = useStore((s) => s.captionAnim);
  const setOn = useStore((s) => s.setCaptionsOn);
  const setStyle = useStore((s) => s.setCaptionStyle);
  const setColor = useStore((s) => s.setCaptionColor);
  const setAnim = useStore((s) => s.setCaptionAnim);
  const resetColors = useStore((s) => s.resetCaptionColors);
  const [open, setOpen] = useState(false);
  const btnRef = useRef<HTMLButtonElement>(null);
  // the panel renders in a portal (so the timeline's overflow can't clip it); anchor it just above the trigger
  const [pos, setPos] = useState<{ right: number; bottom: number }>({ right: 16, bottom: 56 });
  const toggle = () => {
    const r = btnRef.current?.getBoundingClientRect();
    if (r) setPos({ right: Math.max(8, Math.round(window.innerWidth - r.right)), bottom: Math.round(window.innerHeight - r.top + 6) });
    setOpen((o) => !o);
  };

  // close on a real outside click — NOT a full-screen overlay (that collapsed the menu the moment the
  // native colour picker was dismissed, so you could only ever land one click before it vanished).
  // The OS colour dialog is a separate window, so dragging in it never dispatches a page mousedown.
  useEffect(() => {
    if (!open) return;
    const onDown = (e: MouseEvent) => {
      const t = e.target as HTMLElement;
      if (t.closest("[data-caption-menu]") || t.closest("[data-caption-toggle]")) return;
      setOpen(false);
    };
    const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") setOpen(false); };
    window.addEventListener("mousedown", onDown);
    window.addEventListener("keydown", onKey);
    return () => { window.removeEventListener("mousedown", onDown); window.removeEventListener("keydown", onKey); };
  }, [open]);

  const base = captionStyleById(styleId || "tiktok-pop");
  const effectiveAnim = anim || base.anim || "none";
  const hasOverrides = Object.keys(colors).length > 0;

  // a color row reading the merged "current value" back from the same resolver the renderer uses
  const ColorRow = ({ label, k }: { label: string; k: ColorKey }) => {
    const presetVal =
      k === "active" ? base.activeColor :
      k === "base" ? base.color :
      base.box?.color ?? FALLBACK_HIGHLIGHT;
    const cur = colors[k] ?? presetVal;
    const overridden = colors[k] != null;
    return (
      <div className="flex items-center justify-between px-2 py-1">
        <span className="text-[12px] text-fg-muted">{label}</span>
        <div className="flex items-center gap-1.5">
          <label title={`${label} color`}
            className="relative grid h-6 w-6 cursor-pointer place-items-center overflow-hidden rounded-md ring-1 ring-inset ring-fg/20"
            style={{ background: HEX6.test(cur) ? cur : "#000000" }}>
            <Pipette size={10} className="pointer-events-none drop-shadow" style={{ color: "#fff", mixBlendMode: "difference" }} />
            <input type="color" value={HEX6.test(cur) ? cur : "#000000"}
              onInput={(e) => setColor(k, (e.target as HTMLInputElement).value)}
              onChange={(e) => setColor(k, e.target.value)}
              className="absolute inset-0 cursor-pointer opacity-0" />
          </label>
          <button title="Reset to preset" onClick={() => setColor(k, null)}
            className={"grid h-5 w-5 place-items-center rounded text-fg-muted hover:bg-white/5 " + (overridden ? "opacity-100" : "opacity-0 pointer-events-none")}>
            <X size={11} />
          </button>
        </div>
      </div>
    );
  };

  return (
    <div className="relative flex items-center">
      <button title="Toggle captions" onClick={() => setOn(!on)}
        className={"flex h-7 items-center gap-1 rounded px-1.5 text-[11px] font-semibold " + (on ? "text-primary" : "text-fg-muted hover:text-fg")}>
        <Captions size={15} /> {on ? "ON" : "OFF"}
      </button>
      <button ref={btnRef} data-caption-toggle title="Caption style" onClick={toggle} className="grid h-7 w-4 place-items-center rounded text-fg-muted hover:bg-white/5"><ChevronUp size={12} /></button>
      {open && createPortal(
        <>
          <div data-caption-menu style={{ position: "fixed", right: pos.right, bottom: pos.bottom }} className="z-[60] max-h-[28rem] w-72 overflow-y-auto rounded-lg border border-border bg-surface-raised p-2 shadow-xl">
            {/* header + self-contained on/off */}
            <div className="flex items-center justify-between px-1 pb-2 pt-1">
              <span className="text-[13px] font-semibold text-fg">Captions</span>
              <button onClick={() => setOn(!on)}
                className={"rounded-full px-2 py-0.5 text-[11px] font-semibold " + (on ? "bg-primary/15 text-primary" : "bg-white/5 text-fg-muted")}>
                {on ? "ON" : "OFF"}
              </button>
            </div>

            {/* style gallery — live "Aa" preview of the MERGED look (preset + overrides) */}
            <div className="eyebrow px-1 pb-1">Style</div>
            <div className="grid grid-cols-2 gap-1.5 px-0.5">
              {CAPTION_STYLES.map((s) => {
                const m = resolveCaptionStyle(s, colors);
                const swatchBg = m.box?.color ?? (m.bg ? m.bg.color : "#0d0d0f");
                return (
                  <button key={s.id} onClick={() => { setStyle(s.id); setOn(true); }}
                    className={"flex flex-col items-center gap-1 rounded-md border border-border/60 p-2 hover:bg-primary/5 " + (s.id === styleId ? "ring-2 ring-primary" : "")}>
                    <span className="grid h-9 w-full place-items-center rounded text-[15px] font-extrabold"
                      style={{
                        fontFamily: m.fontFamily, fontWeight: m.fontWeight as number,
                        color: m.activeColor, background: swatchBg,
                        textTransform: m.uppercase ? "uppercase" : "none",
                        WebkitTextStroke: m.stroke ? `${Math.min(2, m.stroke.width / 4)}px ${m.stroke.color}` : undefined,
                      } as React.CSSProperties}>Aa</span>
                    <span className="text-[10px] leading-tight text-fg-muted">{s.label}</span>
                  </button>
                );
              })}
            </div>

            {/* animation picker — "" chip means "use this style's signature anim" */}
            <div className="eyebrow px-1 pb-1 pt-3">Animation</div>
            <div className="flex flex-wrap gap-1 px-0.5">
              <button onClick={() => setAnim("")}
                className={"rounded px-2 py-1 text-[11px] " + (!anim ? "bg-primary/15 text-primary" : "text-fg-muted hover:bg-white/5")}>
                Auto
              </button>
              {CAPTION_ANIMS.map((a) => (
                <button key={a.id} onClick={() => setAnim(a.id)}
                  className={"rounded px-2 py-1 text-[11px] " + (anim === a.id ? "bg-primary/15 text-primary" : "text-fg-muted hover:bg-white/5")}>
                  {a.label}
                </button>
              ))}
            </div>
            {!anim && (
              <div className="px-1 pt-1 text-[10px] text-fg-muted">Using “{base.label}” default ({effectiveAnim}).</div>
            )}

            {/* color overrides — ride on top of the chosen preset */}
            <div className="flex items-center justify-between px-1 pb-1 pt-3">
              <span className="eyebrow">Colors</span>
              {hasOverrides && (
                <button onClick={resetColors} className="text-[10px] text-fg-muted hover:text-fg">Reset</button>
              )}
            </div>
            <ColorRow label="Active word" k="active" />
            <ColorRow label="Base text" k="base" />
            <ColorRow label="Highlight" k="highlight" />
          </div>
        </>,
        document.body,
      )}
    </div>
  );
}
