// 长任务（jobs）轮询纯逻辑：把松散 `GET /jobs/{id}` 响应安全收窄成 JobView，
// 并提供一个 setTimeout 轮询状态机的纯 reducer（C3.5 / ARCH §7.4）。
// schema 把 GET /jobs/{id} 标成 {[k]:unknown}（T0.3 裸端点），这里安全narrow。

// 后端 job 状态机（C3.5）：queued → running → done|failed。
export type JobStatus = "queued" | "running" | "done" | "failed";

export interface JobView {
  id: string;
  kind: string;
  status: JobStatus;
  progress: number;
  result: Record<string, unknown> | null;
  error: string | null;
}

function asString(v: unknown, fallback = ""): string {
  return typeof v === "string" ? v : fallback;
}

function asStatus(v: unknown): JobStatus {
  return v === "running" || v === "done" || v === "failed" || v === "queued"
    ? v
    : "queued";
}

function asProgress(v: unknown): number {
  if (typeof v !== "number" || !Number.isFinite(v)) return 0;
  return Math.min(100, Math.max(0, Math.round(v)));
}

function asResult(v: unknown): Record<string, unknown> | null {
  return typeof v === "object" && v !== null && !Array.isArray(v)
    ? (v as Record<string, unknown>)
    : null;
}

// 把松散 GET /jobs/{id} 响应收窄成 JobView（缺字段给安全默认）。
export function narrowJob(raw: unknown): JobView {
  const dict =
    typeof raw === "object" && raw !== null ? (raw as Record<string, unknown>) : {};
  return {
    id: asString(dict["id"]),
    kind: asString(dict["kind"]),
    status: asStatus(dict["status"]),
    progress: asProgress(dict["progress"]),
    result: asResult(dict["result"]),
    error: typeof dict["error"] === "string" ? (dict["error"] as string) : null,
  };
}

// 学文风 job 完成态的 result：{version, dims_count}（C3 扩 work 摘要）。
export interface StyleLearnResult {
  version: number | null;
  dimsCount: number | null;
}

export function styleLearnResult(job: JobView): StyleLearnResult {
  const r = job.result ?? {};
  const version = typeof r["version"] === "number" ? r["version"] : null;
  const dimsCount =
    typeof r["dims_count"] === "number" ? r["dims_count"] : null;
  return { version, dimsCount };
}

// 轮询状态机：polling（queued/running）→ done | error（done/failed）。
export type PollStatus = "polling" | "done" | "error";

export interface PollState {
  status: PollStatus;
  progress: number;
  job: JobView | null;
  error: string | null;
}

export const initialPollState: PollState = {
  status: "polling",
  progress: 0,
  job: null,
  error: null,
};

export type PollAction =
  | { type: "tick"; job: JobView }
  | { type: "fail"; error: string };

// 纯 reducer：吃一次轮询结果，映射成轮询状态。
// done → 终态 done；failed → 终态 error（用 job.error 文案）；其余 → 继续 polling。
export function reducePoll(state: PollState, action: PollAction): PollState {
  if (action.type === "fail") {
    return { ...state, status: "error", error: action.error };
  }
  const { job } = action;
  if (job.status === "done") {
    return { status: "done", progress: 100, job, error: null };
  }
  if (job.status === "failed") {
    return {
      status: "error",
      progress: job.progress,
      job,
      error: job.error ?? "任务失败",
    };
  }
  return { status: "polling", progress: job.progress, job, error: null };
}

// 是否终态（停止轮询）。
export function isTerminal(status: JobStatus): boolean {
  return status === "done" || status === "failed";
}
