import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { vi } from "vitest";
import PaymentForm from "./PaymentForm";
import i18n from "../i18n";

vi.mock("../api/client", () => ({
  apiPost: vi.fn(),
}));

const { apiPost } = await import("../api/client");

describe("PaymentForm", () => {
  beforeEach(async () => {
    vi.clearAllMocks();
    await i18n.changeLanguage("en");
    Object.defineProperty(globalThis, "crypto", {
      value: { randomUUID: () => "uuid-1" },
      configurable: true,
    });
  });

  it("validates source details for stc pay", async () => {
    render(<PaymentForm bookingId="12" />);
    fireEvent.click(screen.getByRole("button", { name: "Pay now" }));
    expect(
      await screen.findByText("Mobile number is required for stc pay.")
    ).toBeInTheDocument();
  });

  it("reuses idempotency key on retry", async () => {
    apiPost.mockRejectedValueOnce(new Error("fail"));
    apiPost.mockResolvedValueOnce({ id: "ok" });
    render(<PaymentForm bookingId="12" />);

    fireEvent.change(screen.getByLabelText("Source value"), {
      target: { value: "+966500000000" },
    });
    fireEvent.click(screen.getByRole("button", { name: "Pay now" }));
    await screen.findByText("fail");

    fireEvent.click(screen.getByRole("button", { name: "Pay now" }));
    await waitFor(() => {
      expect(apiPost).toHaveBeenCalledTimes(2);
    });
    const firstPayload = apiPost.mock.calls[0][1];
    const secondPayload = apiPost.mock.calls[1][1];
    expect(firstPayload.idempotency_key).toBe("uuid-1");
    expect(secondPayload.idempotency_key).toBe("uuid-1");
  });

  it("redirects when response includes redirect_url", async () => {
    const assign = vi.fn();
    Object.defineProperty(window.location, "assign", {
      value: assign,
      configurable: true,
    });
    apiPost.mockResolvedValueOnce({ redirect_url: "https://pay.test/redirect" });
    render(<PaymentForm bookingId="12" />);

    fireEvent.change(screen.getByLabelText("Source value"), {
      target: { value: "+966500000000" },
    });
    fireEvent.click(screen.getByRole("button", { name: "Pay now" }));

    await waitFor(() => {
      expect(assign).toHaveBeenCalledWith("https://pay.test/redirect");
    });
  });

  it("disables submit while loading", async () => {
    let resolveRequest;
    apiPost.mockImplementationOnce(
      () =>
        new Promise((resolve) => {
          resolveRequest = resolve;
        })
    );
    render(<PaymentForm bookingId="12" />);

    fireEvent.change(screen.getByLabelText("Source value"), {
      target: { value: "+966500000000" },
    });
    const button = screen.getByRole("button", { name: "Pay now" });
    fireEvent.click(button);
    expect(button).toBeDisabled();

    resolveRequest({ id: "done" });
    await waitFor(() => {
      expect(button).not.toBeDisabled();
    });
  });
});
