import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { MemoryRouter } from "react-router-dom";
import { ApiError, api } from "../api";
import { usePollingResource } from "../hooks/usePollingResource";
import { VisitorTakeTicketForm } from "./VisitorTakeTicketPage";

vi.mock("../hooks/usePollingResource", () => ({ usePollingResource: vi.fn() }));

const mockedUsePollingResource = vi.mocked(usePollingResource);

beforeEach(() => {
  mockedUsePollingResource.mockReturnValue({
    data: {
      projects: [{ id: "project-a", name: "云岭漂流", status: "RUNNING", visitor_notice: "请在入口附近等候。", min_party_size: 1, max_party_size: 8 }],
    },
    loading: false,
    refreshing: false,
    error: null,
    offline: false,
    lastClientSuccessAt: new Date().toISOString(),
    refresh: vi.fn(),
    resourceKey: "visitor-public-projects",
  });
});

describe("VisitorTakeTicketForm", () => {
  it("允许清空默认同行人数后输入新值", () => {
    render(<MemoryRouter><VisitorTakeTicketForm /></MemoryRouter>);

    const partySizeInput = screen.getByRole("spinbutton", { name: /同行人数/ });
    expect(partySizeInput).toHaveValue(1);

    fireEvent.change(partySizeInput, { target: { value: "" } });
    expect(partySizeInput).toHaveValue(null);

    fireEvent.change(partySizeInput, { target: { value: "5" } });
    expect(partySizeInput).toHaveValue(5);
  });

  it("creates a ticket from the visitor form and offers the private status page", async () => {
    const createTicket = vi.spyOn(api, "publicCreateTicket").mockResolvedValueOnce({
      ticket: { id: "ticket-1", ticket_number: "00021", status: "WAITING", phone_last4: "8000", party_size: 3 },
      public_token: "visitor-token",
      public_url: "/visitor/visitor-token",
      revision: 4,
    });

    try {
      render(<MemoryRouter><VisitorTakeTicketForm /></MemoryRouter>);

      expect(screen.queryByText(/一个号码对应您填写的同行人数/)).not.toBeInTheDocument();
      expect(screen.getByLabelText("排队项目")).toHaveValue("project-a");
      fireEvent.change(screen.getByLabelText("手机号"), { target: { value: "13800138000" } });
      fireEvent.change(screen.getByLabelText("姓氏（选填）"), { target: { value: "李" } });
      fireEvent.change(screen.getByRole("spinbutton", { name: /同行人数/ }), { target: { value: "3" } });
      fireEvent.click(screen.getByRole("button", { name: "创建排队号码" }));

      await waitFor(() => expect(screen.getByRole("status")).toHaveTextContent("00021"));
      expect(createTicket).toHaveBeenCalledWith("project-a", {
        phone: "13800138000",
        party_size: 3,
        last_name: "李",
        honorific: "",
        allow_duplicate: false,
      }, expect.any(String));
      expect(screen.getByRole("link", { name: "查看排队状态" })).toHaveAttribute("href", "/visitor/visitor-token");
    } finally {
      createTicket.mockRestore();
    }
  });

  it("requires explicit confirmation before creating another active ticket for the same phone", async () => {
    const createTicket = vi.spyOn(api, "publicCreateTicket")
      .mockRejectedValueOnce(new ApiError("该手机号已有活动号码，请确认后继续", 409, undefined, "DUPLICATE_PHONE"))
      .mockResolvedValueOnce({
        ticket: { id: "ticket-2", ticket_number: "00022", status: "WAITING", phone_last4: "8000", party_size: 1 },
        public_token: "visitor-token-2",
        revision: 5,
      });

    try {
      render(<MemoryRouter><VisitorTakeTicketForm /></MemoryRouter>);
      fireEvent.change(screen.getByLabelText("手机号"), { target: { value: "13800138000" } });
      fireEvent.click(screen.getByRole("button", { name: "创建排队号码" }));

      await waitFor(() => expect(screen.getByText("该手机号已有活动号码")).toBeVisible());
      expect(screen.getByRole("button", { name: "确认继续取号" })).toBeVisible();
      fireEvent.click(screen.getByRole("button", { name: "确认继续取号" }));

      await waitFor(() => expect(screen.getByRole("status")).toHaveTextContent("00022"));
      expect(createTicket).toHaveBeenLastCalledWith("project-a", {
        phone: "13800138000",
        party_size: 1,
        last_name: "",
        honorific: "",
        allow_duplicate: true,
      }, expect.any(String));
    } finally {
      createTicket.mockRestore();
    }
  });

  it("shows the Retry-After wait without clearing the visitor form", async () => {
    const createTicket = vi.spyOn(api, "publicCreateTicket").mockRejectedValueOnce(
      new ApiError("取号次数过多，请稍后再试", 429, undefined, "PUBLIC_TICKET_RATE_LIMITED", 17),
    );

    try {
      render(<MemoryRouter><VisitorTakeTicketForm /></MemoryRouter>);
      const phoneInput = screen.getByLabelText("手机号");
      fireEvent.change(phoneInput, { target: { value: "13800138000" } });
      fireEvent.click(screen.getByRole("button", { name: "创建排队号码" }));

      await waitFor(() => expect(screen.getByText(/17 秒后重试/)).toBeVisible());
      expect(phoneInput).toHaveValue("13800138000");
      expect(screen.getByRole("button", { name: /请等待 17 秒/ })).toBeDisabled();
    } finally {
      createTicket.mockRestore();
    }
  });
});
