"use client";

import { useCallback, useEffect, useRef, useState } from "react";

import { api } from "@/lib/api/client";
import { useToast } from "@/components/Toast";
import { useJobPoll } from "@/lib/jobs/useJobPoll";
import { styleLearnResult } from "@/lib/jobs/job";
import {
  buildLearnRequest,
  normalizeFingerprint,
  type Fingerprint,
  type StyleLearnMode,
} from "./style";

export interface UseStyleLearn {
  // 提交中（POST /style 受理）或轮询中。
  busy: boolean;
  pollStatus: ReturnType<typeof useJobPoll>["status"] | "idle";
  progress: number;
  fingerprint: Fingerprint | null;
  // 学文风：POST /style → 拿 job_id → 轮询 → done 后拉最新指纹。
  learn: (
    projectId: string,
    samples: string[],
    mode: StyleLearnMode,
  ) => Promise<boolean>;
}

function errorCode(error: unknown): string | undefined {
  if (typeof error !== "object" || error === null) return undefined;
  const env = error as { error?: { code?: unknown } };
  return typeof env.error?.code === "string" ? env.error.code : undefined;
}

// 学文风编排：受理（202 job_id）→ useJobPoll 轮询 → done 拉 GET /style 展示指纹。
export function useStyleLearn(initial: Fingerprint | null): UseStyleLearn {
  const [fingerprint, setFingerprint] = useState<Fingerprint | null>(initial);
  const [submitting, setSubmitting] = useState(false);
  const [pollStatus, setPollStatus] = useState<
    ReturnType<typeof useJobPoll>["status"] | "idle"
  >("idle");
  // projectId 用 ref 而非 state：done 边沿的 effect 须读到「最近一次 learn 传入的」
  // 而非闭包捕获的旧值（修 stale-closure）。learn 同步写 ref，effect 同步读。
  const projectIdRef = useRef<string | null>(null);
  const poll = useJobPoll();
  const toast = useToast();
  // 仅在提交过一次学文风后才反映轮询状态（initialPollState.status 默认 "polling"）。
  const startedRef = useRef(false);

  // 轮询完成 → 拉最新指纹；失败 → toast。
  // 依赖 poll.status / poll.error / toast（均稳定或随状态变化），projectId 经 ref 取最新。
  useEffect(() => {
    if (!startedRef.current) return;
    setPollStatus(poll.status);
    const projectId = projectIdRef.current;
    if (poll.status === "done" && projectId) {
      void refetchFingerprint(projectId).then((fp) => {
        if (fp) setFingerprint(fp);
        toast("文风指纹已更新。", "success");
      });
    }
    if (poll.status === "error") {
      toast(`学文风失败：${poll.error ?? "未知原因"}`, "error");
    }
  }, [poll.status, poll.error, toast]);

  const learn = useCallback<UseStyleLearn["learn"]>(
    async (pid, samples, mode) => {
      setSubmitting(true);
      projectIdRef.current = pid;
      try {
        const { data, error } = await api.POST("/projects/{project_id}/style", {
          params: { path: { project_id: pid } },
          body: buildLearnRequest(samples, mode),
        });
        if (error || !data) {
          const code = errorCode(error);
          toast(
            code === "LLM_UNAVAILABLE"
              ? "未配置提供商，请先去设置页连一家。"
              : "学文风受理失败，请稍后重试。",
            "error",
          );
          return false;
        }
        startedRef.current = true;
        poll.poll(data.job_id);
        setPollStatus("polling");
        return true;
      } finally {
        setSubmitting(false);
      }
    },
    [poll, toast],
  );

  return {
    busy: submitting || pollStatus === "polling",
    pollStatus,
    progress: poll.progress,
    fingerprint,
    learn,
  };
}

// 客户端拉最新指纹（done 后刷新展示）；404/失败 → null。
async function refetchFingerprint(
  projectId: string,
): Promise<Fingerprint | null> {
  const { data, error } = await api.GET("/projects/{project_id}/style", {
    params: { path: { project_id: projectId } },
  });
  if (error || !data) return null;
  return normalizeFingerprint(data);
}

// 仅供测试/复用：保证 job done result 的版本回显（不阻断 UI）。
export function learnSummary(
  poll: ReturnType<typeof useJobPoll>,
): { version: number | null; dimsCount: number | null } | null {
  if (poll.status !== "done" || !poll.job) return null;
  return styleLearnResult(poll.job);
}
