import { beforeEach, describe, expect, it, vi } from "vitest";
import {
  axelSearchRowToCandidate,
  resolveAxelMothershipCandidates,
  resolveAxelMothershipSuggest,
} from "@/lib/axel/candidates";
import { AxelHttpClient } from "@/lib/axel/client";

describe("axelSearchRowToCandidate", () => {
  it("display_label 与 axel description 一致，option_id 保留原始 placeId", () => {
    const row = {
      placeId: "ChIJ4cLf10jGwoARBQWdZHer2OQ",
      description: "123 Main Street, Los Angeles, CA, USA",
      mainText: "123 Main Street",
      secondaryText: "Los Angeles, CA, USA",
    };
    const candidate = axelSearchRowToCandidate(row, {
      street: "123 Main St",
      city: "Los Angeles",
      state: "CA",
      zip: "90001",
    });
    expect(candidate?.option_id).toBe("ChIJ4cLf10jGwoARBQWdZHer2OQ");
    expect(candidate?.display_label).toBe(
      "123 Main Street, Los Angeles, CA, USA",
    );
    expect(candidate?.street).toContain("123");
  });
});

describe("resolveAxelMothershipCandidates", () => {
  beforeEach(() => {
    vi.restoreAllMocks();
    vi.stubEnv("AXEL_CANDIDATE_VERIFY_TOP_K", "3");
  });

  function makeSearchRow(suffix: string) {
    return {
      placeId: `ChIJ-${suffix}`,
      description: `${suffix} Main Street, Dallas, TX, USA`,
      mainText: `${suffix} Main Street`,
      secondaryText: "Dallas, TX, USA",
    };
  }

  it("仅对前 3 条候选 fetchPlace 校验，其余默认可选", async () => {
    const fetchPlace = vi.fn().mockResolvedValue({ placeId: "ok" });
    const searchLocation = vi
      .fn()
      .mockResolvedValueOnce([
        makeSearchRow("1"),
        makeSearchRow("2"),
        makeSearchRow("3"),
        makeSearchRow("4"),
        makeSearchRow("5"),
      ])
      .mockResolvedValueOnce([makeSearchRow("d1")]);

    vi.spyOn(AxelHttpClient, "create").mockResolvedValue({
      searchLocation,
      fetchPlace,
    } as unknown as AxelHttpClient);

    const result = await resolveAxelMothershipCandidates({
      pickup: {
        street: "1 Main St",
        city: "Dallas",
        state: "TX",
        zip: "75201",
      },
      delivery: {
        street: "2 Oak Ave",
        city: "Los Angeles",
        state: "CA",
        zip: "90001",
      },
    });

    expect(result.pickup_candidates).toHaveLength(5);
    expect(result.delivery_candidates).toHaveLength(1);
    expect(fetchPlace).toHaveBeenCalledTimes(4);
    expect(result.pickup_candidates[0]?.selectable).toBe(true);
    expect(result.pickup_candidates[3]?.selectable).toBe(true);
    expect(result.pickup_candidates[4]?.selectable).toBe(true);
  });

  it("前 K 条均失败时，未校验候选仍可使 assert 通过", async () => {
    const fetchPlace = vi
      .fn()
      .mockRejectedValueOnce(new Error("place 404"))
      .mockRejectedValueOnce(new Error("place 404"))
      .mockRejectedValueOnce(new Error("place 404"))
      .mockResolvedValueOnce({ placeId: "ChIJ-d1" });
    const searchLocation = vi
      .fn()
      .mockResolvedValueOnce([
        makeSearchRow("bad1"),
        makeSearchRow("bad2"),
        makeSearchRow("bad3"),
        makeSearchRow("good-tail"),
      ])
      .mockResolvedValueOnce([makeSearchRow("d1")]);

    vi.spyOn(AxelHttpClient, "create").mockResolvedValue({
      searchLocation,
      fetchPlace,
    } as unknown as AxelHttpClient);

    const result = await resolveAxelMothershipCandidates({
      pickup: {
        street: "99 Main St",
        city: "Dallas",
        state: "TX",
        zip: "75201",
      },
      delivery: {
        street: "1 Oak",
        city: "LA",
        state: "CA",
        zip: "90001",
      },
    });

    expect(result.pickup_candidates[0]?.selectable).toBe(false);
    expect(result.pickup_candidates[3]?.selectable).toBe(true);
    expect(fetchPlace).toHaveBeenCalledTimes(4);
  });
});

describe("resolveAxelMothershipSuggest", () => {
  beforeEach(() => {
    vi.restoreAllMocks();
    vi.stubEnv("AXEL_CANDIDATE_VERIFY_TOP_K", "3");
  });

  it("仅映射 Axel googlePlacesResults，无 placeId 丢弃，并对 TopK fetchPlace", async () => {
    const fetchPlace = vi.fn().mockResolvedValue({ placeId: "ok" });
    const searchLocation = vi.fn().mockResolvedValue([
      {
        placeId: "ChIJ-a",
        description: "100 A St, LA, CA, USA",
        mainText: "100 A St",
        secondaryText: "LA, CA, USA",
      },
      {
        placeId: "",
        description: "本系统不应出现的假地址",
        mainText: "fake",
        secondaryText: "Nowhere",
      },
    ]);

    vi.spyOn(AxelHttpClient, "create").mockResolvedValue({
      searchLocation,
      fetchPlace,
    } as unknown as AxelHttpClient);

    const list = await resolveAxelMothershipSuggest("100 A St");
    expect(searchLocation).toHaveBeenCalledWith("100 A St");
    expect(list).toHaveLength(1);
    expect(list[0]?.option_id).toBe("ChIJ-a");
    expect(fetchPlace).toHaveBeenCalledTimes(1);
  });
});
