import { describe, expect, it, vi } from "vitest";
import { pollQuoteUntilDone } from "@/hooks/use-quote-polling";
import {
  POLL_INTERVAL_MS,
  POLL_TIMEOUT_MS,
} from "@/lib/frontend/constants";
import type { QuoteDetail } from "@/lib/frontend/types";

function processingQuote(): QuoteDetail {
  return {
    quote_id: "QTE_test",
    request_id: "req-1",
    status: "processing",
    currency: "USD",
  };
}

function doneQuote(): QuoteDetail {
  return {
    quote_id: "QTE_test",
    request_id: "req-1",
    status: "done",
    currency: "USD",
    is_realtime: true,
    quotes: [],
  };
}

describe("pollQuoteUntilDone", () => {
  it("前 3 次网络失败第 4 次成功 → done", async () => {
    let calls = 0;
    const result = await pollQuoteUntilDone(async () => {
      calls += 1;
      if (calls < 4) {
        return { ok: false };
      }
      return { ok: true, data: doneQuote() };
    });
    expect(result.type).toBe("done");
    if (result.type === "done") {
      expect(result.quote.status).toBe("done");
    }
    expect(calls).toBe(4);
  });

  it("超过 POLL_TIMEOUT_MS 仍 processing → timeout", async () => {
    vi.useFakeTimers();
    const promise = pollQuoteUntilDone(async () => ({
      ok: true,
      data: processingQuote(),
    }));

    await vi.advanceTimersByTimeAsync(
      POLL_TIMEOUT_MS + POLL_INTERVAL_MS,
    );
    const result = await promise;
    expect(result.type).toBe("timeout");
    vi.useRealTimers();
  });

  it("failed 状态 → error 含可读文案", async () => {
    const result = await pollQuoteUntilDone(async () => ({
      ok: true,
      data: {
        ...doneQuote(),
        status: "failed",
        error_code: "ADDRESS_SUGGESTION_NOT_FOUND",
        error_message: "未找到用户确认的 MotherShip 地址",
      },
    }));
    expect(result.type).toBe("error");
    if (result.type === "error") {
      expect(result.message).toBe("未找到用户确认的 MotherShip 地址");
    }
  });

  it("processing 超过 10s 后使用更短轮询间隔", async () => {
    vi.useFakeTimers();
    let calls = 0;
    const intervals: number[] = [];
    let last = Date.now();

    const promise = pollQuoteUntilDone(async () => {
      const now = Date.now();
      if (calls > 0) {
        intervals.push(now - last);
      }
      last = now;
      calls += 1;
      if (calls < 7) {
        return { ok: true, data: processingQuote() };
      }
      return { ok: true, data: doneQuote() };
    });

    for (let i = 0; i < 6; i += 1) {
      await vi.advanceTimersByTimeAsync(2_000);
    }
    await vi.advanceTimersByTimeAsync(800);
    const result = await promise;
    expect(result.type).toBe("done");
    expect(intervals.some((gap) => gap <= 800)).toBe(true);
    vi.useRealTimers();
  });
});
