// Kimi Code OAuth device-flow 连接态纯逻辑（C3 扩 K1.3，K1.4 前端）。
// 把「连接状态查询」「device 启动响应」「job 轮询结果」收窄/归一成一个
// 可渲染的连接阶段（connect phase），组件只读结果、不含分支逻辑。
// 纯函数 + node-env 单测；token 永不出现（job 结果只 {connected, provider}）。

import type { JobView, PollState } from "@/lib/jobs/job";
import type {
  OAuthStartResponse,
  OAuthStatusResponse,
} from "@/lib/api/types";

// Kimi Code 是 OAuth 订阅 plan 提供商（与 API-key provider `kimi` 分离）。
export const KIMI_CODE_PROVIDER = "kimi-code";
export const KIMI_CODE_MODEL = "kimi-for-coding";

// 连接流阶段：
// - idle：未发起且未连接（展示「连接」按钮）。
// - connected：状态查询/job 完成显示已连接（展示「断开」）。
// - awaiting：已拿 device code，正在等待用户在浏览器授权 + 轮询 job。
// - error：device 启动失败 / 轮询失败 / 过期 / 拒绝（展示错误 + 允许重试）。
export type ConnectPhase = "idle" | "awaiting" | "connected" | "error";

// device 启动后用户面要展示的信息（无 token）。
export interface DeviceDisplay {
  userCode: string;
  verificationUri: string;
  verificationUriComplete: string | null;
  expiresIn: number;
  interval: number;
}

// 把 OAuthStartResponse 收窄成展示用 DeviceDisplay（缺字段给安全默认）。
export function toDeviceDisplay(res: OAuthStartResponse): DeviceDisplay {
  return {
    userCode: res.user_code,
    verificationUri: res.verification_uri,
    verificationUriComplete: res.verification_uri_complete ?? null,
    expiresIn: typeof res.expires_in === "number" ? res.expires_in : 0,
    interval: typeof res.interval === "number" ? res.interval : 5,
  };
}

// 优先打开的授权 URL：有 complete（带 user_code 预填）就用它，否则裸 verification_uri。
export function authOpenUrl(device: DeviceDisplay): string {
  return device.verificationUriComplete ?? device.verificationUri;
}

// 连接状态（GET .../oauth/status）收窄。
export interface ConnectionStatus {
  connected: boolean;
  expiresAt: string | null;
}

export function toConnectionStatus(
  res: OAuthStatusResponse,
): ConnectionStatus {
  return {
    connected: res.connected === true,
    expiresAt: typeof res.expires_at === "string" ? res.expires_at : null,
  };
}

// kimi_oauth job 完成态的 result：{connected, provider}（**绝无 token**）。
export function jobConnected(job: JobView): boolean {
  return job.result?.["connected"] === true;
}

// 把「是否已发起连接 + 轮询状态」映射成连接阶段。
// - 未发起（started=false）：connected ? connected : idle。
// - 已发起：done 且 job.connected → connected；error → error；否则 awaiting。
export function connectPhase(args: {
  started: boolean;
  connected: boolean;
  poll: PollState;
}): ConnectPhase {
  const { started, connected, poll } = args;
  if (!started) {
    return connected ? "connected" : "idle";
  }
  if (poll.status === "done") {
    return poll.job !== null && jobConnected(poll.job) ? "connected" : "error";
  }
  if (poll.status === "error") {
    return "error";
  }
  return "awaiting";
}

// 把 ISO8601 过期时刻格式化成可读文案（无效/缺省→null）。
export function formatExpiresAt(iso: string | null): string | null {
  if (!iso) return null;
  const ms = Date.parse(iso);
  if (Number.isNaN(ms)) return null;
  return new Date(ms).toLocaleString("zh-CN", {
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
  });
}
