"use client";

import { useState } from "react";
import JSZip from "jszip";

// Auto-ingest the project assets bundle (project.zip): extract in-browser, upload
// each file, and map by name → project + scene fields (the §11.5 convention).
// After this the admin can still modify any of them in the scene editor.
//
//   p.jpg/png/webp → project image      p.mp4 → project demo      p.svg → project colour svg
//   s{i}.jpg/png   → scene[i] image     s{i}.mp4 → scene[i] demo  s{i}.svg → scene[i] colour svg
//   <name>.mp3 (not "sfx") → project default music (stored as a project asset)
//   (s{i} maps to the i-th scene by sort order — scenes must exist first, via the scan)

interface Scene {
  id: string; key: string; title: string; localized_title?: string | null; scene_type: string;
  image?: string | null; demo?: string | null; scene_color_svg?: string | null; snapshot_url?: string | null;
  generate_kf: boolean; default_duration_sec?: number | null; min_duration_sec?: number | null;
  max_duration_sec?: number | null; overlap_at_end_sec: number; can_handle_duration: boolean;
  manual_color_selection: boolean; sort: number; is_active: boolean;
}

const isImg = (e: string) => /^(jpg|jpeg|png|webp|gif)$/.test(e);

export function ProjectMediaBundle({ projectId, onDone }: { projectId: string; onDone: () => void }) {
  const [busy, setBusy] = useState(false);
  const [log, setLog] = useState<string[]>([]);
  const [err, setErr] = useState<string | null>(null);
  const add = (m: string) => setLog((l) => [...l, m]);

  const uploadBlob = async (filename: string, blob: Blob): Promise<string> => {
    const fd = new FormData();
    fd.append("file", new File([blob], filename));
    const r = await fetch("/api/admin/files/upload", { method: "POST", body: fd });
    const d = await r.json().catch(() => null);
    if (!r.ok || !d?.url) throw new Error(`بارگذاری «${filename}» ناموفق بود`);
    return d.url as string;
  };

  const run = async (file: File) => {
    setBusy(true); setErr(null); setLog([]);
    try {
      const zip = await JSZip.loadAsync(file);
      // scenes (sorted by sort) — s{i} maps to the i-th
      const sr = await fetch(`/api/admin/resource/scenes?project_id=${projectId}`, { cache: "no-store" }).then((x) => x.json()).catch(() => null);
      const scenes: Scene[] = (Array.isArray(sr) ? sr : sr?.data ?? []).slice().sort((a: Scene, b: Scene) => a.sort - b.sort);
      add(`صحنه‌های موجود: ${scenes.length}`);

      const projPatch: Record<string, string> = {};
      const sceneOver: Record<number, { image?: string; demo?: string; scene_color_svg?: string }> = {};
      let music: { url: string; name: string } | null = null;

      const entries = Object.values(zip.files).filter((f) => !f.dir && !/(^|\/)(__MACOSX|\._)/.test(f.name));
      for (const entry of entries) {
        const base = (entry.name.split("/").pop() || "").toLowerCase();
        const ext = (base.match(/\.([^.]+)$/)?.[1]) || "";
        const stem = base.replace(/\.[^.]+$/, "");
        const blob = await entry.async("blob");
        const url = await uploadBlob(base, blob);
        add(`↑ ${base}`);

        const sm = stem.match(/^s(\d+)$/);
        if (stem === "p") {
          if (isImg(ext)) projPatch.image = url;
          else if (ext === "mp4") projPatch.full_demo = url;
          else if (ext === "svg") projPatch.shared_colors_svg = url;
        } else if (sm) {
          const i = parseInt(sm[1], 10);
          sceneOver[i] = sceneOver[i] || {};
          if (isImg(ext)) sceneOver[i].image = url;
          else if (ext === "mp4") sceneOver[i].demo = url;
          else if (ext === "svg") sceneOver[i].scene_color_svg = url;
        } else if (ext === "mp3" && stem !== "sfx") {
          music = { url, name: base };
        }
        // demo.mp4 / sfx / other → ignored (sfx ships inside the render footage)
      }

      // project fields
      if (Object.keys(projPatch).length) {
        await fetch(`/api/admin/resource/projects/${projectId}`, {
          method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify(projPatch),
        });
        add(`پروژه به‌روزرسانی شد (${Object.keys(projPatch).join(", ")})`);
      }

      // scene fields (PUT full scene with the new media merged in)
      let sceneHits = 0;
      for (const key of Object.keys(sceneOver)) {
        const i = parseInt(key, 10);
        const scene = scenes[i - 1];
        if (!scene) { add(`⚠ صحنهٔ ${i} وجود ندارد — رد شد`); continue; }
        const o = sceneOver[i];
        const body = {
          key: scene.key, title: scene.title, localized_title: scene.localized_title ?? null, scene_type: scene.scene_type,
          image: o.image ?? scene.image ?? null, demo: o.demo ?? scene.demo ?? null,
          scene_color_svg: o.scene_color_svg ?? scene.scene_color_svg ?? null, snapshot_url: scene.snapshot_url ?? null,
          generate_kf: scene.generate_kf, default_duration_sec: scene.default_duration_sec,
          min_duration_sec: scene.min_duration_sec, max_duration_sec: scene.max_duration_sec,
          overlap_at_end_sec: scene.overlap_at_end_sec ?? 0, can_handle_duration: scene.can_handle_duration,
          manual_color_selection: scene.manual_color_selection, sort: scene.sort, is_active: scene.is_active,
        };
        await fetch(`/api/admin/resource/scenes/${scene.id}`, {
          method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body),
        });
        sceneHits++;
      }
      if (sceneHits) add(`${sceneHits.toLocaleString("fa-IR")} صحنه با رسانه به‌روزرسانی شد`);

      // music → project asset
      if (music) {
        await fetch(`/api/admin/resource/projects/${projectId}/assets`, {
          method: "POST", headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ name: music.name, kind: "audio", url: music.url, sort: 0 }),
        });
        add(`موسیقی افزوده شد: ${music.name}`);
      }

      add("✓ بستهٔ رسانه با موفقیت اعمال شد");
      onDone();
    } catch (e) {
      setErr(e instanceof Error ? e.message : "اعمال بستهٔ رسانه ناموفق بود");
    } finally {
      setBusy(false);
    }
  };

  return (
    <div className="rounded-lg border border-[#262b40] p-3">
      <div className="flex items-center justify-between gap-2">
        <div>
          <p className="text-[11px] font-medium text-gray-300">بستهٔ رسانه (zip)</p>
          <p className="text-[10px] text-gray-500">تصاویر/دموهای صحنه‌ها و پروژه + موسیقی را خودکار اعمال می‌کند (p.jpg، p.mp4، s۱.jpg…). بعداً قابل ویرایش است.</p>
        </div>
        <label className="shrink-0 cursor-pointer rounded-lg bg-indigo-600 px-3 py-1.5 text-xs font-medium text-white hover:bg-indigo-500">
          {busy ? "در حال اعمال…" : "بارگذاری بستهٔ رسانه"}
          <input type="file" accept=".zip" className="hidden" disabled={busy}
            onChange={(e) => { const f = e.target.files?.[0]; if (f) run(f); e.currentTarget.value = ""; }} />
        </label>
      </div>
      {err && <p className="mt-2 rounded bg-red-500/10 px-2 py-1 text-[11px] text-red-300">{err}</p>}
      {log.length > 0 && (
        <ul className="mt-2 max-h-32 space-y-0.5 overflow-y-auto text-[10px] text-gray-500" dir="ltr">
          {log.map((l, i) => <li key={i}>{l}</li>)}
        </ul>
      )}
    </div>
  );
}
