// 2 · 拆解爆款 — 任务列表 + 实时进度 + 拆解结果
// 选片与发起拆解已下沉到 /collect；本页只承担「执行 + 查看」。

const fmtElapsed = (startISO, endISO) => {
  if (!startISO || !endISO) return null;
  const ms = new Date(endISO) - new Date(startISO);
  if (!isFinite(ms) || ms < 0) return null;
  const sec = Math.round(ms / 1000);
  if (sec < 60) return `${sec}s`;
  const m = Math.floor(sec / 60);
  const s = sec % 60;
  if (m < 60) return s ? `${m}m${s}s` : `${m}m`;
  const h = Math.floor(m / 60);
  const mm = m % 60;
  return mm ? `${h}h${mm}m` : `${h}h`;
};

const fmtFinished = (iso) => {
  if (!iso) return null;
  const d = new Date(iso);
  if (isNaN(d.getTime())) return null;
  const M = String(d.getMonth() + 1).padStart(2, "0");
  const D = String(d.getDate()).padStart(2, "0");
  const h = String(d.getHours()).padStart(2, "0");
  const m = String(d.getMinutes()).padStart(2, "0");
  return `${M}-${D} ${h}:${m}`;
};

const TeardownDetail = () => {
  // ─── 文案二创独立链路（URL 带 ?text_rewrite_job=xxx 时显示进度卡）───
  const trJobId = useTextRewriteJobIdFromQuery();

  // ─── 任务面板 ───
  const [jobs, setJobs] = React.useState([]);
  const [jobsLoading, setJobsLoading] = React.useState(false);
  const [activeJobId, setActiveJobId] = React.useState(null);
  const [jobProgress, setJobProgress] = React.useState(null); // { step, pct, message }
  const [jobStatus, setJobStatus] = React.useState(""); // pending|running|completed|failed
  const disposeRef = React.useRef(null);

  // ─── 结果内嵌折叠面板 ───
  const [resultExpanded, setResultExpanded] = React.useState(false);

  // ─── 重试 failed 任务 ───
  const [retryBusy, setRetryBusy] = React.useState(false);
  const [retryHint, setRetryHint] = React.useState(null); // {kind, msg}

  const retryActive = async () => {
    if (!activeJobId || retryBusy) return;
    setRetryBusy(true);
    setRetryHint(null);
    try {
      await API.jobs.retry(activeJobId);
      setRetryHint({ kind: "ok", msg: "已重新调度，几秒后会回到 running" });
      // 自动刷一下任务列表 + 进度状态
      await loadJobs();
    } catch (e) {
      setRetryHint({ kind: "err", msg: String(e.message || e).slice(0, 80) });
    } finally {
      setRetryBusy(false);
      // 6 秒后清掉提示
      setTimeout(() => setRetryHint(null), 6000);
    }
  };

  // ─── 初始化加载 ───
  React.useEffect(() => {
    loadJobs();
    const t = setInterval(loadJobs, 5000);
    return () => clearInterval(t);
  }, []);

  async function loadJobs() {
    setJobsLoading(true);
    try {
      const d = await API.jobs.list();
      setJobs(d.items || []);
    } catch (_) {}
    finally { setJobsLoading(false); }
  }

  // 当前任务失败后不要继续霸占中栏：只要队列里还有 running / pending，
  // 页面就自动跟过去。失败任务本身已经是终态，不会阻塞后端并发。
  React.useEffect(() => {
    if (!jobs.length) return;
    const live = jobs.find(j => j.status === "running" || j.status === "pending");
    const active = activeJobId ? jobs.find(j => j.job_id === activeJobId) : null;

    if (!activeJobId) {
      if (live) setActiveJobId(live.job_id);
      return;
    }
    if (!active) {
      setActiveJobId(live ? live.job_id : null);
      return;
    }
    if (active.status === "failed" && live && live.job_id !== activeJobId) {
      setActiveJobId(live.job_id);
      setResultExpanded(false);
    }
  }, [jobs, activeJobId]);

  // 当前 activeJobId 是否对应一个已完成的任务 —— 用于决定是否在中栏渲染内联结果折叠卡。
  // 优先看本地 jobStatus（SSE 实时同步），其次回退到 jobs 列表里的快照。
  const resultJobId = React.useMemo(() => {
    if (!activeJobId) return null;
    if (jobStatus === "completed") return activeJobId;
    const j = jobs.find(x => x.job_id === activeJobId);
    return j && j.status === "completed" ? activeJobId : null;
  }, [activeJobId, jobStatus, jobs]);

  // ─── SSE 订阅当前任务 ───
  React.useEffect(() => {
    if (!activeJobId) {
      if (disposeRef.current) { disposeRef.current(); disposeRef.current = null; }
      setJobProgress(null);
      setJobStatus("");
      return;
    }
    if (disposeRef.current) { disposeRef.current(); disposeRef.current = null; }

    // 用 jobs 列表里的快照 init，避免每次切换都闪一下"任务已排队"；
    // SSE 第一帧 status / progress 会很快覆盖。
    const known = jobs.find(j => j.job_id === activeJobId);
    setJobProgress(known?.progress || { step: "queued", pct: 0, message: "任务已排队" });
    setJobStatus(known?.status || "pending");

    disposeRef.current = subscribeJobProgress(activeJobId, (kind, payload) => {
      if (kind === "progress") {
        setJobProgress(payload);
        setJobStatus(prev => (prev === "completed" || prev === "failed") ? prev : "running");
      }
      if (kind === "status") {
        setJobStatus(payload.status || "running");
      }
      if (kind === "done") {
        setJobStatus(payload.status || "completed");
        setJobProgress(prev => ({ ...prev, step: payload.status, pct: 100, message: payload.error || "已完成" }));
        loadJobs();
        if (disposeRef.current) { disposeRef.current(); disposeRef.current = null; }
      }
    });

    return () => {
      if (disposeRef.current) { disposeRef.current(); disposeRef.current = null; }
    };
    // jobs 故意不进依赖：5s 轮询会频繁变更，加进来会让 SSE 反复重连。
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [activeJobId]);

  const cancelActive = async () => {
    if (!activeJobId) return;
    try {
      await API.jobs.cancel(activeJobId);
      setJobStatus("failed");
      setJobProgress(prev => ({ ...prev, step: "failed", message: "用户取消" }));
      loadJobs();
    } catch (_) {}
  };

  const openResult = (jobId) => {
    if (jobId && jobId !== activeJobId) setActiveJobId(jobId);
    setResultExpanded(true);
  };

  const activeJob = jobs.find(j => j.job_id === activeJobId);

  return (
    <>
      <Topbar
        crumbs={["2 · 拆解爆款", activeJobId ? `任务 ${activeJobId.slice(0, 8)}…` : "选择任务"]}
        right={<>
          <span className="pill"><Icon name="check" size={10}/>{jobs.length} 个任务</span>
          <button className="btn ghost" onClick={loadJobs}>
            <Icon name="refresh" size={11}/>刷新
          </button>
        </>}
      />

      <div className="main-body">
        {/* 中：进度 + 结果 */}
        <div className="col grow scroll" style={{
          padding: "14px 14px 20px", gap: 12, background: "var(--bg-0)", minWidth: 0,
        }}>
          {/* 文案二创独立链路进度（URL 带 ?text_rewrite_job=xxx 时显示）*/}
          {trJobId && <TextRewriteProgress jobId={trJobId} currentRoute="teardown"/>}

          {!activeJobId && (
            <div className="card col center" style={{ padding: "60px 20px", gap: 10, textAlign: "center" }}>
              <Icon name="layers" size={24} style={{ color: "var(--fg-3)" }} />
              <div style={{ fontSize: 13, color: "var(--fg-1)", fontWeight: 500 }}>请在右侧任务列表选择一个任务</div>
              <div style={{ fontSize: 11, color: "var(--fg-3)", lineHeight: 1.7 }}>
                运行中显示进度，已完成显示拆解报告
                <br/>
                新发起的拆解请前往 <a href="/collect" style={{ color: "var(--cyan)" }}>收集爆款</a> 页面
              </div>
            </div>
          )}

          {/* 拆解进度（仅在有 active job 时显示）*/}
          {activeJobId && jobProgress && (
            <div className="card" style={{ overflow: "hidden" }}>
              <div className="card-hd">
                <span className="card-title">拆解进度</span>
                <span className="card-sub">
                  实时同步 · 任务 {activeJobId.slice(0, 8)}…
                  {activeJob?.title && ` · ${activeJob.title.slice(0, 40)}`}
                </span>
              </div>
              <div className="col" style={{ padding: 12, gap: 8 }}>
                <div className="row between" style={{ alignItems: "center", gap: 8 }}>
                  <span style={{ fontSize: 12, color: "var(--fg-1)", lineHeight: 1.4, flex: 1, minWidth: 0 }}>
                    {jobProgress.message || "—"}
                  </span>
                  <span className={`tag ${jobStatus==="completed"?"green":jobStatus==="failed"?"pink":"cyan"}`} style={{ fontSize: 9 }}>
                    {jobStatus==="completed"?"已完成":jobStatus==="failed"?"已终止":jobStatus==="running"?"进行中":"排队中"}
                  </span>
                </div>
                <div className="bar" style={{ height: 4 }}>
                  <span style={{
                    width: `${Math.max(0, Math.min(100, jobProgress.pct || 0))}%`,
                    background: jobStatus==="failed"?"var(--pink)":jobStatus==="completed"?"var(--green)":"var(--cyan)",
                    transition: "width .3s",
                  }} />
                </div>
                {(jobStatus === "running" || jobStatus === "pending" || jobStatus === "completed") && (
                  <div className="row gap-8" style={{ paddingTop: 2 }}>
                    {(jobStatus === "running" || jobStatus === "pending") && (
                      <button className="btn sm" onClick={cancelActive} style={{ color: "var(--pink)" }}>
                        <Icon name="close" size={10}/>取消
                      </button>
                    )}
                    {jobStatus === "completed" && (
                      <button className="btn sm primary" onClick={() => openResult(activeJobId)}>
                        <Icon name={resultExpanded ? "down" : "right"} size={10}/>
                        {resultExpanded ? "折叠结果" : "查看结果"}
                      </button>
                    )}
                  </div>
                )}
                {jobStatus === "failed" && (
                  <div className="col gap-6" style={{ paddingTop: 2 }}>
                    <div className="row gap-8" style={{ alignItems: "center" }}>
                      <button className="btn sm primary"
                              disabled={retryBusy}
                              onClick={() => retryActive()}
                              style={{ background: "var(--cyan)", color: "var(--bg-0)" }}>
                        <Icon name="refresh" size={10}/>
                        {retryBusy ? "重新调度中…" : "重试任务"}
                      </button>
                      {retryHint && (
                        <span style={{ fontSize: 10, color: retryHint.kind === "ok"
                          ? "var(--green)" : "var(--pink)" }}>
                          {retryHint.msg}
                        </span>
                      )}
                    </div>
                    <div style={{ fontSize: 10.5, color: "var(--fg-3)", lineHeight: 1.6 }}>
                      已自动终止；点"重试"会保留已下载的视频和已抽出的音频，从失败 stage 续跑。
                    </div>
                  </div>
                )}
              </div>
            </div>
          )}

          {/* 拆解结果（内联折叠面板）*/}
          {resultJobId && (
            <div className="card">
              <div
                className="card-hd"
                onClick={() => setResultExpanded(e => !e)}
                style={{ cursor: "pointer", userSelect: "none" }}
                title={resultExpanded ? "点击折叠" : "点击展开查看完整拆解报告"}
              >
                <Icon
                  name={resultExpanded ? "down" : "right"}
                  size={11}
                  style={{ color: "var(--fg-3)" }}
                />
                <span className="card-title">拆解结果</span>
                <span className="card-sub">
                  任务 {resultJobId.slice(0, 8)}… · 点击{resultExpanded ? "折叠" : "展开"}
                </span>
              </div>
              {resultExpanded && (
                <div style={{ padding: "12px 14px 18px" }}>
                  <ResultReport key={resultJobId} jobId={resultJobId} />
                </div>
              )}
            </div>
          )}
        </div>

        {/* 右：任务列表 */}
        <div className="col scroll" style={{
          width: 280, flexShrink: 0, padding: "12px 12px 20px", gap: 10,
          borderLeft: "1px solid var(--line-soft)", background: "var(--bg-0)",
        }}>
          <div className="row between" style={{ padding: "0 2px 4px" }}>
            <span className="kpi-l">任务列表</span>
            <span className="mono" style={{ fontSize: 10, color: "var(--fg-3)" }}>{jobs.length} 条</span>
          </div>

          {jobs.slice(0, 50).map(j => (
            <div
              key={j.job_id}
              onClick={() => setActiveJobId(j.job_id)}
              title={j.status === "failed" ? "失败任务已终止，不会阻塞其他任务；点击查看错误" : "点击查看实时进度 / 拆解结果"}
              className="col gap-4"
              style={{
                padding: 8, borderRadius: 5, cursor: "pointer",
                background: j.job_id === activeJobId ? "color-mix(in oklch, var(--cyan) 6%, var(--bg-1))" : "var(--bg-1)",
                border: `1px solid ${j.job_id === activeJobId ? "var(--cyan)" : "var(--line-1)"}`,
              }}>
              <div className="row between">
                <span className="mono" style={{ fontSize: 10, color: "var(--fg-3)" }}>{j.job_id.slice(0, 10)}…</span>
                <span className={`tag ${j.status==="completed"?"green":j.status==="failed"?"pink":"cyan"}`} style={{ fontSize: 9 }}>
                  {j.status==="completed"?"完成":j.status==="failed"?"终止":j.status==="running"?"进行中":"排队"}
                </span>
              </div>
              <div style={{
                fontSize: 11, color: "var(--fg-0)", fontWeight: 500,
                overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
              }}>
                {j.title || j.video_filename || "未命名"}
              </div>
              <div className="row between" style={{ fontSize: 9.5, color: "var(--fg-3)" }}>
                <span>{j.source}</span>
                <span>{j.industry || "general"}</span>
              </div>
              {(() => {
                const isTerminal = j.status === "completed" || j.status === "failed";
                const elapsed = isTerminal ? fmtElapsed(j.created_at, j.updated_at) : null;
                const finished = fmtFinished(j.updated_at);
                if (!elapsed && !finished) return null;
                return (
                  <div className="row" style={{ fontSize: 9.5, color: "var(--fg-3)", gap: 6, alignItems: "center" }}>
                    <Icon name="clock" size={9}/>
                    {elapsed && <span>用时 {elapsed}</span>}
                    {elapsed && finished && <span style={{ opacity: .5 }}>·</span>}
                    {finished && <span>{finished}</span>}
                  </div>
                );
              })()}
              {j.status === "completed" && j.has_result && (
                <button
                  className="btn sm"
                  onClick={(e) => { e.stopPropagation(); openResult(j.job_id); }}
                  style={{ alignSelf: "flex-start" }}>
                  <Icon name="ext" size={10}/>查看结果
                </button>
              )}
              {j.error && (
                <div style={{ fontSize: 9.5, color: "var(--pink)", lineHeight: 1.4 }}>{j.error.slice(0, 80)}</div>
              )}
            </div>
          ))}

          {!jobs.length && !jobsLoading && (
            <div style={{ fontSize: 11, color: "var(--fg-3)", padding: 20, textAlign: "center", lineHeight: 1.7 }}>
              暂无拆解任务
              <br/>
              请前往 <a href="/collect" style={{ color: "var(--cyan)" }}>收集爆款</a> 发起
            </div>
          )}
        </div>
      </div>
    </>
  );
};

Object.assign(window, { TeardownDetail });
