"use client";

import { Cable, Copy, Monitor, Radio } from "lucide-react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";

import { LiveProcessLiveLogCard } from "@/components/live-product/LiveProcessLiveLogCard";

type ProcessEntry = { pm2: string; script: string; label: string };

type TFn = (zh: string, en: string) => string;

function isTiktokProcess(e: ProcessEntry) {
  return /tiktok/i.test(e.script) || /tiktok/i.test(e.pm2);
}

type HdmiPreset = { id: string; labelZh: string; labelEn: string; spec: string; hintZh: string; hintEn: string };

const PRESETS: HdmiPreset[] = [
  {
    id: "720p60",
    labelZh: "720p @ 60Hz",
    labelEn: "720p @ 60Hz",
    spec: "1280x720, 59.94/60Hz, RGB/YUV 有限",
    hintZh: "板端 HDMI 输出与采集卡 EDID 对齐；OBS 画布 1280×720。",
    hintEn: "Match SoC HDMI timing to capture card EDID; OBS 1280×720.",
  },
  {
    id: "1080p30",
    labelZh: "1080p @ 30Hz",
    labelEn: "1080p @ 30Hz",
    spec: "1920x1080, 30Hz, 适合 USB 采集带宽紧张场景",
    hintZh: "USB3 采集常更稳；检查线缆长度与屏蔽。",
    hintEn: "Often more stable on USB3 capture; check cable quality.",
  },
  {
    id: "1080p60",
    labelZh: "1080p @ 60Hz",
    labelEn: "1080p @ 60Hz",
    spec: "1920x1080, 60Hz, 高刷转播",
    hintZh: "需确认采集卡与 SoC 同时支持 1080p60；过热会掉帧。",
    hintEn: "Requires 1080p60 on both ends; thermal throttling may drop frames.",
  },
];

const CHECK_KEY = "live-hub-tiktok-hdmi-check-v1";
const NOTES_KEY = "live-hub-tiktok-hdmi-notes-v1";

type Props = {
  t: TFn;
  busy: boolean;
  entries: ProcessEntry[];
  currentProc: string;
  setCurrentProc: (v: string) => void;
  urlConfig: string;
  setUrlConfig: (v: string) => void;
  onRunProcess: (a: "start" | "stop" | "restart") => void;
  onSaveUrlConfig: (content?: string) => void | Promise<void>;
  onCopy: (text: string) => void;
  fetchJson: <T,>(path: string, init?: RequestInit) => Promise<T>;
};

export function LiveTiktokHdmiView({
  t,
  busy,
  entries,
  currentProc,
  setCurrentProc,
  urlConfig,
  setUrlConfig,
  onRunProcess,
  onSaveUrlConfig,
  onCopy,
  fetchJson,
}: Props) {
  const tkEntries = useMemo(() => entries.filter(isTiktokProcess), [entries]);
  const processOptions = tkEntries.length ? tkEntries : entries;
  const [expanded, setExpanded] = useState<string | null>("1080p30");
  const [selectedPreset, setSelectedPreset] = useState<string>("1080p30");
  const [urlReloading, setUrlReloading] = useState(false);
  const [urlAutoRefresh, setUrlAutoRefresh] = useState(true);
  const [urlFetchNote, setUrlFetchNote] = useState<string | null>(null);
  const urlListDirtyRef = useRef(false);
  const [hdmiNotes, setHdmiNotes] = useState("");
  const [checks, setChecks] = useState<Record<string, boolean>>({});

  useEffect(() => {
    urlListDirtyRef.current = false;
  }, [currentProc]);

  const pullUrlConfigFromServer = useCallback(async () => {
    if (!currentProc) return;
    try {
      const data = await fetchJson<{ content?: string }>(
        `/get_url_config?process=${encodeURIComponent(currentProc)}`,
      );
      setUrlConfig(data.content ?? "");
    } catch {
      /* ignore */
    }
  }, [currentProc, fetchJson, setUrlConfig]);

  useEffect(() => {
    if (!currentProc || !urlAutoRefresh) return;
    const id = window.setInterval(() => {
      if (urlListDirtyRef.current) return;
      void pullUrlConfigFromServer();
    }, 8000);
    return () => clearInterval(id);
  }, [currentProc, urlAutoRefresh, pullUrlConfigFromServer]);

  useEffect(() => {
    try {
      const raw = window.localStorage.getItem(CHECK_KEY);
      if (raw) setChecks(JSON.parse(raw) as Record<string, boolean>);
    } catch {
      /* ignore */
    }
    try {
      setHdmiNotes(window.localStorage.getItem(NOTES_KEY) || "");
    } catch {
      /* ignore */
    }
  }, []);

  const persistChecks = useCallback((next: Record<string, boolean>) => {
    setChecks(next);
    try {
      window.localStorage.setItem(CHECK_KEY, JSON.stringify(next));
    } catch {
      /* ignore */
    }
  }, []);

  const persistNotes = (v: string) => {
    setHdmiNotes(v);
    try {
      window.localStorage.setItem(NOTES_KEY, v);
    } catch {
      /* ignore */
    }
  };

  const reloadUrlConfig = async () => {
    if (!currentProc) return;
    setUrlReloading(true);
    setUrlFetchNote(null);
    urlListDirtyRef.current = false;
    try {
      const data = await fetchJson<{ content?: string }>(
        `/get_url_config?process=${encodeURIComponent(currentProc)}`,
      );
      setUrlConfig(data.content ?? "");
      setUrlFetchNote(t("已从服务器读取 URL_config", "Reloaded URL_config from server"));
    } catch (e) {
      setUrlFetchNote((e as Error).message);
    } finally {
      setUrlReloading(false);
    }
  };

  const saveUrlAndClearDirty = async () => {
    try {
      await Promise.resolve(onSaveUrlConfig());
      urlListDirtyRef.current = false;
    } catch {
      /* parent 已 toast */
    }
  };

  const lock = busy || urlReloading;
  const presetLabel = PRESETS.find((p) => p.id === selectedPreset);

  const checklist: { id: string; zh: string; en: string }[] = [
    { id: "cable", zh: "HDMI 线材插紧、方向正确（如需转接头确认规格）", en: "HDMI cable seated; adapter specs OK" },
    { id: "edid", zh: "采集卡与板端分辨率/刷新率一致（见上方预设）", en: "Capture + SoC timing match preset" },
    { id: "usb", zh: "USB 采集盒接 USB3 口，避免过长无屏蔽线", en: "USB3 capture; avoid bad cables" },
    { id: "thermal", zh: "长时间推流注意散热，过热会掉帧黑屏", en: "Thermal headroom for long runs" },
  ];

  return (
    <div className="mx-auto max-w-4xl space-y-6">
      <div className="rounded-2xl border border-cyan-500/25 bg-gradient-to-br from-cyan-500/[0.14] via-zinc-950/80 to-fuchsia-500/10 p-6 shadow-xl shadow-cyan-900/10">
        <div className="flex flex-wrap items-start gap-4">
          <div className="flex items-center gap-3">
            <div className="flex h-11 w-11 items-center justify-center rounded-xl bg-gradient-to-br from-cyan-500/35 to-fuchsia-600/25 ring-1 ring-white/10">
              <Cable className="h-5 w-5 text-cyan-200" />
            </div>
            <div>
              <h2 className="text-lg font-semibold tracking-tight text-white">
                {t("TikTok 无人直播（单路）", "TikTok unmanned (single lane)")}
              </h2>
              <p className="mt-0.5 text-xs text-zinc-500">
                {t(
                  "布局对齐 YouTube 单频道：直播开关 + 源站 + URL_config；无 stream key，输出走 HDMI 硬件链路。",
                  "Same layout as YouTube single: controls + URLs; no stream key — HDMI hardware path.",
                )}
              </p>
            </div>
          </div>
        </div>
      </div>

      <div className="rounded-2xl border border-amber-500/20 bg-zinc-950/60 p-6 ring-1 ring-white/[0.04]">
        <div className="flex items-center gap-2 text-amber-200/90">
          <Radio className="h-4 w-4" />
          <h3 className="text-sm font-semibold text-white">{t("直播开关", "Live control")}</h3>
        </div>
        <label className="mt-4 block text-xs font-semibold uppercase tracking-wider text-zinc-500">
          {t("TikTok 进程（PM2）", "TikTok PM2 process")}
        </label>
        <select
          className="mt-2 w-full rounded-xl border border-white/10 bg-black/40 px-4 py-3 text-sm text-white"
          value={currentProc}
          onChange={(e) => setCurrentProc(e.target.value)}
        >
          {processOptions.map((e) => (
            <option key={e.pm2} value={e.pm2}>
              {e.label} ({e.pm2})
            </option>
          ))}
        </select>
        <div className="mt-4 grid grid-cols-2 gap-2 sm:grid-cols-3">
          {(
            [
              ["start", t("开始直播", "Start"), "bg-emerald-500/20 text-emerald-200 ring-emerald-500/30"],
              ["stop", t("停止直播", "Stop"), "bg-rose-500/15 text-rose-200 ring-rose-500/25"],
              ["restart", t("重新开始", "Restart"), "bg-amber-500/15 text-amber-200 ring-amber-500/25"],
            ] as const
          ).map(([a, label, cls]) => (
            <button
              key={a}
              type="button"
              disabled={lock}
              onClick={() => onRunProcess(a)}
              className={`rounded-xl px-4 py-3 text-sm font-medium ring-1 ${cls}`}
            >
              {label}
            </button>
          ))}
        </div>
        <p className="mt-3 text-center text-[11px] text-zinc-500">
          {t("当前 HDMI 预设（备忘）", "HDMI preset (memo)")}:{" "}
          <span className="font-mono text-cyan-300/90">
            {presetLabel ? t(presetLabel.labelZh, presetLabel.labelEn) : selectedPreset}
          </span>
        </p>
      </div>

      <div className="rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6">
        <h3 className="flex items-center gap-2 text-sm font-semibold text-white">
          <Monitor className="h-4 w-4 text-cyan-400" />
          {t("HDMI 硬件与时序", "HDMI timing")}
        </h3>
        <p className="mt-1 text-xs text-zinc-500">
          {t("点选一路作为现场备忘；与板端 ffmpeg/OBS 采集参数对齐。", "Pick a preset as field memo; match capture settings.")}
        </p>
        <div className="mt-4 grid gap-3 md:grid-cols-3">
          {PRESETS.map((p) => {
            const open = expanded === p.id;
            const sel = selectedPreset === p.id;
            return (
              <button
                key={p.id}
                type="button"
                onClick={() => {
                  setExpanded(open ? null : p.id);
                  setSelectedPreset(p.id);
                }}
                className={`rounded-2xl border p-4 text-left transition ${
                  sel ? "border-cyan-500/50 ring-1 ring-cyan-500/20" : ""
                } ${open ? "border-cyan-500/40 bg-cyan-500/10" : "border-white/[0.08] bg-zinc-950/50 hover:border-white/15"}`}
              >
                <div className="flex items-center gap-2 text-sm font-semibold text-white">
                  <Monitor className="h-4 w-4 text-cyan-400" />
                  {t(p.labelZh, p.labelEn)}
                </div>
                <p className="mt-2 font-mono text-[11px] text-zinc-400">{p.spec}</p>
                {open ? <p className="mt-2 text-xs text-zinc-500">{t(p.hintZh, p.hintEn)}</p> : null}
              </button>
            );
          })}
        </div>

        <div className="mt-6 rounded-xl border border-white/5 bg-black/25 p-4">
          <p className="text-xs font-semibold text-zinc-400">{t("上线前检查清单（本地保存）", "Pre-flight checklist (local)")}</p>
          <ul className="mt-3 space-y-2">
            {checklist.map((c) => (
              <li key={c.id} className="flex items-start gap-2 text-xs text-zinc-400">
                <input
                  type="checkbox"
                  className="mt-0.5 rounded border-white/20 bg-black/40"
                  checked={!!checks[c.id]}
                  onChange={(e) => persistChecks({ ...checks, [c.id]: e.target.checked })}
                />
                <span>{t(c.zh, c.en)}</span>
              </li>
            ))}
          </ul>
          <label className="mt-4 block text-[11px] text-zinc-500">{t("采集卡 / EDID / 走线备忘", "Capture / EDID notes")}</label>
          <textarea
            className="mt-1 min-h-[72px] w-full resize-y rounded-lg border border-white/10 bg-black/40 p-3 text-xs text-zinc-300"
            value={hdmiNotes}
            onChange={(e) => persistNotes(e.target.value)}
            spellCheck={false}
            placeholder="Magewell / OBS 视频采集设备 …"
          />
        </div>
      </div>

      <div className="rounded-2xl border border-white/[0.08] bg-zinc-950/50 p-6">
        <div className="flex flex-wrap items-center justify-between gap-2">
          <h3 className="text-sm font-semibold text-white">{t("直播地址列表 · URL_config.ini", "URL_config.ini")}</h3>
          <button
            type="button"
            className="inline-flex items-center gap-1 text-xs text-cyan-300 hover:text-cyan-200"
            onClick={() => onCopy(urlConfig)}
          >
            <Copy className="h-3.5 w-3.5" />
            {t("复制全文", "Copy all")}
          </button>
        </div>
        <p className="mt-1 text-xs text-zinc-500">
          {t(
            "一行一个地址；可勾选自动从服务器刷新，或点「重新读取」手动同步。",
            "One URL per line; enable auto-refresh or reload from server.",
          )}
        </p>
        <div className="mt-2 flex flex-wrap items-center gap-4 text-xs text-zinc-400">
          <label className="flex cursor-pointer items-center gap-2">
            <input
              type="checkbox"
              className="rounded border-white/20 bg-black/40"
              checked={urlAutoRefresh}
              onChange={(e) => setUrlAutoRefresh(e.target.checked)}
            />
            {t("每 8 秒自动从服务器刷新", "Auto-refresh from server every 8s")}
          </label>
        </div>
        {urlFetchNote ? <p className="mt-2 text-xs text-zinc-500">{urlFetchNote}</p> : null}
        <textarea
          className="mt-4 min-h-[200px] w-full resize-y rounded-xl border border-white/10 bg-black/50 p-4 font-mono text-xs text-zinc-300"
          value={urlConfig}
          onChange={(e) => {
            urlListDirtyRef.current = true;
            setUrlConfig(e.target.value);
          }}
          spellCheck={false}
        />
        <div className="mt-3 flex flex-wrap gap-2">
          <button
            type="button"
            disabled={lock}
            onClick={() => void reloadUrlConfig()}
            className="rounded-xl border border-white/10 bg-white/[0.05] px-4 py-2 text-sm text-zinc-300"
          >
            {t("重新读取", "Reload from server")}
          </button>
          <button
            type="button"
            disabled={lock}
            onClick={() => void saveUrlAndClearDirty()}
            className="rounded-xl bg-cyan-500/20 px-4 py-2 text-sm font-medium text-cyan-100 ring-1 ring-cyan-500/30"
          >
            {t("保存 URL 配置", "Save URL config")}
          </button>
        </div>
      </div>

      <LiveProcessLiveLogCard
        t={t}
        currentProc={currentProc}
        fetchJson={fetchJson}
        urlListText={urlConfig}
        keySuffixUi=""
        showKeyRow={false}
      />
    </div>
  );
}
