import { useCallback, useEffect, useRef, useState } from "react";
import { apiGet, apiPost, apiPostImage, uploadBackground, SearchItem } from "../../api";
import { PageHead, Empty, Loading } from "../../components/ui";
import { IconCheck, IconImage, IconSearch, IconUpload, IconWand } from "../../components/icons";
import { useToast } from "../../lib/toast";

interface ImageInfo {
  has_logo: boolean;
  logo_count: number;
  backdrop_count: number;
  logos: { index: number; url: string }[];
  backdrops: { index: number }[];
}

interface Options {
  title: string;
  bg_mode: string;
  backdrop_index: number;
  text_color: string;
  logo_align: string;
  logo_scale: number;
  darkness: number;
  studio: string;
  studio_position: string;
  new_episodes_tag: boolean;
  season_finale_tag: boolean;
  generate_primary: boolean;
  logo_index: number;
  upload_bg_id: string | null;
}

const DEFAULTS: Options = {
  title: "",
  bg_mode: "backdrop",
  backdrop_index: 0,
  text_color: "#FFFFFF",
  logo_align: "bottom-center",
  logo_scale: 1.3,
  darkness: 0.0,
  studio: "auto",
  studio_position: "top-left",
  new_episodes_tag: false,
  season_finale_tag: false,
  generate_primary: false,
  logo_index: 0,
  upload_bg_id: null,
};

const ALIGNS = ["top-left", "top-center", "top-right", "bottom-left", "bottom-center", "bottom-right"];
const STUDIOS = ["auto", "none", "netflix", "appletv", "paramountplus", "hbo", "disney", "hulu"];
const POSITIONS = ["top-left", "top-right", "bottom-left", "bottom-right"];

export default function Generator() {
  const toast = useToast();
  const [query, setQuery] = useState("");
  const [results, setResults] = useState<SearchItem[]>([]);
  const [searching, setSearching] = useState(false);
  const [selected, setSelected] = useState<SearchItem | null>(null);
  const [imageInfo, setImageInfo] = useState<ImageInfo | null>(null);
  const [opts, setOpts] = useState<Options>(DEFAULTS);
  const [preview, setPreview] = useState<string | null>(null);
  const [rendering, setRendering] = useState(false);
  const [applying, setApplying] = useState(false);
  const debounceRef = useRef<number>();

  const set = <K extends keyof Options>(k: K, v: Options[K]) => setOpts((o) => ({ ...o, [k]: v }));

  async function search(e?: React.FormEvent) {
    e?.preventDefault();
    if (!query.trim()) return;
    setSearching(true);
    try {
      const d = await apiGet<{ items: SearchItem[] }>(
        `/api/search?q=${encodeURIComponent(query.trim())}&limit=40`
      );
      setResults(d.items);
    } catch (err: any) {
      toast(err.message, "err");
    } finally {
      setSearching(false);
    }
  }

  async function select(item: SearchItem) {
    setSelected(item);
    setPreview(null);
    setImageInfo(null);
    setOpts({ ...DEFAULTS, title: item.name, studio: item.auto_studio || "auto" });
    try {
      const info = await apiGet<ImageInfo>(`/api/images/${item.id}`);
      setImageInfo(info);
    } catch (err: any) {
      toast(err.message, "err");
    }
  }

  const buildBody = useCallback(
    () => ({ item_id: selected?.id, ...opts }),
    [selected, opts]
  );

  const generate = useCallback(async () => {
    if (!selected) return;
    setRendering(true);
    try {
      const { url } = await apiPostImage("/api/generate", buildBody());
      setPreview((prev) => {
        if (prev) URL.revokeObjectURL(prev);
        return url;
      });
    } catch (err: any) {
      toast(err.message, "err");
    } finally {
      setRendering(false);
    }
  }, [selected, buildBody, toast]);

  // Auto-regenerate the preview shortly after any option changes.
  useEffect(() => {
    if (!selected) return;
    window.clearTimeout(debounceRef.current);
    debounceRef.current = window.setTimeout(generate, 350);
    return () => window.clearTimeout(debounceRef.current);
  }, [selected, opts]); // eslint-disable-line react-hooks/exhaustive-deps

  async function apply() {
    if (!selected) return;
    setApplying(true);
    try {
      const res = await apiPost("/api/apply", buildBody());
      toast(`Applied to Emby (thumb ${res.thumb_code})`, "ok");
    } catch (err: any) {
      toast(err.message, "err");
    } finally {
      setApplying(false);
    }
  }

  async function onUpload(file: File) {
    try {
      const { upload_id } = await uploadBackground(file);
      setOpts((o) => ({ ...o, bg_mode: "upload", upload_bg_id: upload_id }));
      toast("Background uploaded", "ok");
    } catch (err: any) {
      toast(err.message, "err");
    }
  }

  return (
    <>
      <PageHead title="Thumbnail Generator" icon={<IconImage />} />

      <div className="workbench">
        {/* search column */}
        <div className="panel" style={{ display: "flex", flexDirection: "column", maxHeight: "calc(100vh - 200px)" }}>
          <div style={{ padding: 14, borderBottom: "1px solid var(--border)" }}>
            <form className="search-inner" onSubmit={search}>
              <IconSearch />
              <input className="input" placeholder="Search movies & series…" value={query} onChange={(e) => setQuery(e.target.value)} />
            </form>
          </div>
          <div style={{ overflowY: "auto", padding: 8 }}>
            {searching ? (
              <Loading />
            ) : results.length === 0 ? (
              <Empty icon={<IconSearch />}>Search your Emby library to begin.</Empty>
            ) : (
              results.map((r) => (
                <div key={r.id} className={`result-item ${selected?.id === r.id ? "active" : ""}`} onClick={() => select(r)}>
                  <img className="result-poster" src={r.poster_url} loading="lazy" alt="" />
                  <div className="grow">
                    <div className="result-name">{r.name}</div>
                    <div className="result-sub">
                      <span>{r.year || "—"}</span>
                      <span>·</span>
                      <span>{r.type}</span>
                      {r.has_logo && <span className="badge badge-ok">logo</span>}
                    </div>
                  </div>
                </div>
              ))
            )}
          </div>
        </div>

        {/* preview column */}
        <div className="preview-shell">
          {!selected ? (
            <Empty icon={<IconImage />}>Select an item to preview a thumbnail.</Empty>
          ) : (
            <>
              <div className="preview-frame" style={{ aspectRatio: "16 / 9", position: "relative" }}>
                {preview ? <img src={preview} alt="preview" /> : <Loading />}
                {rendering && preview && (
                  <div style={{ position: "absolute", top: 10, right: 10 }}>
                    <span className="spinner" />
                  </div>
                )}
              </div>
              <div className="row" style={{ width: "100%" }}>
                <button className="btn grow" onClick={generate} disabled={rendering}>
                  <IconWand /> Regenerate
                </button>
                <button className="btn btn-primary grow" onClick={apply} disabled={applying || !preview}>
                  {applying ? <span className="spinner" /> : <IconCheck />} Apply to Emby
                </button>
              </div>
            </>
          )}
        </div>

        {/* controls column */}
        <div className="panel scroll-col" style={{ maxHeight: "calc(100vh - 200px)" }}>
          <div className="panel-head">
            <h3>Controls</h3>
          </div>
          <div className="panel-body col" style={{ gap: 16 }}>
            {!selected ? (
              <p className="hint">Pick an item first.</p>
            ) : (
              <>
                <div className="field">
                  <label className="field-label">Title</label>
                  <input className="input" value={opts.title} onChange={(e) => set("title", e.target.value)} />
                </div>

                <div className="field">
                  <label className="field-label">Background</label>
                  <div className="seg">
                    <button className={`seg-btn ${opts.bg_mode === "backdrop" ? "active" : ""}`} onClick={() => set("bg_mode", "backdrop")}>
                      Backdrop
                    </button>
                    <button className={`seg-btn ${opts.bg_mode === "upload" ? "active" : ""}`} onClick={() => opts.upload_bg_id && set("bg_mode", "upload")} disabled={!opts.upload_bg_id}>
                      Upload
                    </button>
                  </div>
                  <label className="btn btn-sm" style={{ marginTop: 4 }}>
                    <IconUpload /> Upload background
                    <input type="file" accept="image/*" hidden onChange={(e) => e.target.files?.[0] && onUpload(e.target.files[0])} />
                  </label>
                </div>

                {opts.bg_mode === "backdrop" && imageInfo && imageInfo.backdrop_count > 1 && (
                  <div className="field">
                    <label className="field-label">
                      Backdrop <span>{opts.backdrop_index + 1}/{imageInfo.backdrop_count}</span>
                    </label>
                    <input
                      type="range"
                      min={0}
                      max={imageInfo.backdrop_count - 1}
                      value={opts.backdrop_index}
                      onChange={(e) => set("backdrop_index", +e.target.value)}
                    />
                  </div>
                )}

                {imageInfo && imageInfo.logo_count > 1 && (
                  <div className="field">
                    <label className="field-label">
                      Logo <span>{opts.logo_index + 1}/{imageInfo.logo_count}</span>
                    </label>
                    <input type="range" min={0} max={imageInfo.logo_count - 1} value={opts.logo_index} onChange={(e) => set("logo_index", +e.target.value)} />
                  </div>
                )}

                <div className="field">
                  <label className="field-label">Logo position</label>
                  <div className="seg">
                    {ALIGNS.map((a) => (
                      <button key={a} className={`seg-btn ${opts.logo_align === a ? "active" : ""}`} onClick={() => set("logo_align", a)}>
                        {a.replace("-", " ")}
                      </button>
                    ))}
                  </div>
                </div>

                <div className="field">
                  <label className="field-label">
                    Logo scale <span className="mono">{opts.logo_scale.toFixed(2)}×</span>
                  </label>
                  <input type="range" min={0.5} max={2.5} step={0.05} value={opts.logo_scale} onChange={(e) => set("logo_scale", +e.target.value)} />
                </div>

                <div className="field">
                  <label className="field-label">
                    Darkness <span className="mono">{Math.round(opts.darkness * 100)}%</span>
                  </label>
                  <input type="range" min={0} max={1} step={0.05} value={opts.darkness} onChange={(e) => set("darkness", +e.target.value)} />
                </div>

                <div className="field">
                  <label className="field-label">Text color</label>
                  <div className="row">
                    <input type="color" value={opts.text_color} onChange={(e) => set("text_color", e.target.value)} />
                    <input className="input grow" value={opts.text_color} onChange={(e) => set("text_color", e.target.value)} />
                  </div>
                </div>

                <div className="field">
                  <label className="field-label">Studio logo</label>
                  <select className="select" value={opts.studio} onChange={(e) => set("studio", e.target.value)}>
                    {STUDIOS.map((s) => (
                      <option key={s} value={s}>
                        {s}
                      </option>
                    ))}
                  </select>
                </div>

                {opts.studio !== "none" && (
                  <div className="field">
                    <label className="field-label">Studio position</label>
                    <div className="seg">
                      {POSITIONS.map((p) => (
                        <button key={p} className={`seg-btn ${opts.studio_position === p ? "active" : ""}`} onClick={() => set("studio_position", p)}>
                          {p.replace("-", " ")}
                        </button>
                      ))}
                    </div>
                  </div>
                )}

                {selected.type === "Series" && (
                  <div className="row wrap">
                    <button className={`chip ${opts.new_episodes_tag ? "active" : ""}`} onClick={() => set("new_episodes_tag", !opts.new_episodes_tag)}>
                      New episodes
                    </button>
                    <button className={`chip ${opts.season_finale_tag ? "active" : ""}`} onClick={() => set("season_finale_tag", !opts.season_finale_tag)}>
                      Season finale
                    </button>
                  </div>
                )}
              </>
            )}
          </div>
        </div>
      </div>
    </>
  );
}
