import { describe, expect, it } from "vitest";

import type { JobView, PollState } from "@/lib/jobs/job";
import {
  authOpenUrl,
  connectPhase,
  formatExpiresAt,
  jobConnected,
  KIMI_CODE_MODEL,
  KIMI_CODE_PROVIDER,
  toConnectionStatus,
  toDeviceDisplay,
} from "./kimiOauth";

const poll = (over: Partial<PollState>): PollState => ({
  status: "polling",
  progress: 0,
  job: null,
  error: null,
  ...over,
});

const job = (over: Partial<JobView>): JobView => ({
  id: "j1",
  kind: "kimi_oauth",
  status: "done",
  progress: 100,
  result: null,
  error: null,
  ...over,
});

describe("KIMI_CODE constants", () => {
  it("uses the OAuth provider + coding model names", () => {
    expect(KIMI_CODE_PROVIDER).toBe("kimi-code");
    expect(KIMI_CODE_MODEL).toBe("kimi-for-coding");
  });
});

describe("toDeviceDisplay", () => {
  it("maps start response fields", () => {
    const d = toDeviceDisplay({
      job_id: "abc",
      user_code: "WXYZ-1234",
      verification_uri: "https://auth.kimi.com/device",
      verification_uri_complete: "https://auth.kimi.com/device?code=WXYZ-1234",
      expires_in: 600,
      interval: 5,
    });
    expect(d).toEqual({
      userCode: "WXYZ-1234",
      verificationUri: "https://auth.kimi.com/device",
      verificationUriComplete: "https://auth.kimi.com/device?code=WXYZ-1234",
      expiresIn: 600,
      interval: 5,
    });
  });

  it("defaults missing complete uri to null", () => {
    const d = toDeviceDisplay({
      job_id: "abc",
      user_code: "CODE",
      verification_uri: "https://auth.kimi.com/device",
      verification_uri_complete: null,
      expires_in: 600,
      interval: 5,
    });
    expect(d.verificationUriComplete).toBeNull();
  });
});

describe("authOpenUrl", () => {
  it("prefers the complete uri when present", () => {
    expect(
      authOpenUrl({
        userCode: "C",
        verificationUri: "https://auth.kimi.com/device",
        verificationUriComplete: "https://auth.kimi.com/device?code=C",
        expiresIn: 600,
        interval: 5,
      }),
    ).toBe("https://auth.kimi.com/device?code=C");
  });

  it("falls back to the plain uri", () => {
    expect(
      authOpenUrl({
        userCode: "C",
        verificationUri: "https://auth.kimi.com/device",
        verificationUriComplete: null,
        expiresIn: 600,
        interval: 5,
      }),
    ).toBe("https://auth.kimi.com/device");
  });
});

describe("toConnectionStatus", () => {
  it("narrows connected + expires_at", () => {
    expect(
      toConnectionStatus({ connected: true, expires_at: "2026-07-01T00:00:00Z" }),
    ).toEqual({ connected: true, expiresAt: "2026-07-01T00:00:00Z" });
  });

  it("defaults non-string expires_at to null", () => {
    expect(toConnectionStatus({ connected: false })).toEqual({
      connected: false,
      expiresAt: null,
    });
  });
});

describe("jobConnected", () => {
  it("true only when result.connected === true (no token expected)", () => {
    expect(jobConnected(job({ result: { connected: true, provider: "kimi-code" } }))).toBe(
      true,
    );
    expect(jobConnected(job({ result: { connected: false } }))).toBe(false);
    expect(jobConnected(job({ result: null }))).toBe(false);
  });
});

describe("connectPhase", () => {
  it("not started + not connected → idle", () => {
    expect(
      connectPhase({ started: false, connected: false, poll: poll({}) }),
    ).toBe("idle");
  });

  it("not started + connected (status query) → connected", () => {
    expect(
      connectPhase({ started: false, connected: true, poll: poll({}) }),
    ).toBe("connected");
  });

  it("started + polling → awaiting", () => {
    expect(
      connectPhase({
        started: true,
        connected: false,
        poll: poll({ status: "polling" }),
      }),
    ).toBe("awaiting");
  });

  it("started + done + job.connected → connected", () => {
    expect(
      connectPhase({
        started: true,
        connected: false,
        poll: poll({
          status: "done",
          job: job({ result: { connected: true, provider: "kimi-code" } }),
        }),
      }),
    ).toBe("connected");
  });

  it("started + done but job not connected → error", () => {
    expect(
      connectPhase({
        started: true,
        connected: false,
        poll: poll({ status: "done", job: job({ result: { connected: false } }) }),
      }),
    ).toBe("error");
  });

  it("started + poll error (expired/denied/network) → error", () => {
    expect(
      connectPhase({
        started: true,
        connected: false,
        poll: poll({ status: "error", error: "授权已过期" }),
      }),
    ).toBe("error");
  });
});

describe("formatExpiresAt", () => {
  it("returns null for null/invalid input", () => {
    expect(formatExpiresAt(null)).toBeNull();
    expect(formatExpiresAt("not-a-date")).toBeNull();
  });

  it("formats a valid ISO timestamp to a non-empty string", () => {
    const out = formatExpiresAt("2026-07-01T08:30:00Z");
    expect(typeof out).toBe("string");
    expect(out).not.toBe("");
  });
});
