import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { vi } from "vitest";
import { MemoryRouter, Route, Routes } from "react-router-dom";
import BookPage from "./BookPage";
import { AuthProvider } from "../contexts/AuthContext";
import i18n from "../i18n";

vi.mock("../components/ProtectedRoute", () => ({
  default: ({ children }) => <>{children}</>,
}));

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

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

function renderBook(initialEntries = ["/book?salon=1"]) {
  return render(
    <AuthProvider>
      <MemoryRouter initialEntries={initialEntries}>
        <Routes>
          <Route path="/book" element={<BookPage />} />
          <Route path="/pay" element={<div>Pay Page</div>} />
        </Routes>
      </MemoryRouter>
    </AuthProvider>
  );
}

const salonFixture = {
  id: 1,
  name: "Riyadh Salon",
  services: [
    { id: 10, name: "Cut", duration_minutes: 60, price_amount: 120, currency: "SAR" },
  ],
  staff: [{ id: 99, name: "Mona" }],
};

describe("BookPage", () => {
  beforeEach(async () => {
    vi.clearAllMocks();
    apiGet.mockResolvedValue(salonFixture);
    await i18n.changeLanguage("en");
  });

  it("validates required fields", async () => {
    renderBook();
    await screen.findByText("Riyadh Salon");
    fireEvent.click(screen.getByRole("button", { name: "Confirm booking" }));
    expect(screen.getByText("Please fill all required fields.")).toBeInTheDocument();
  });

  it("submits booking and redirects to payment", async () => {
    apiPost.mockResolvedValueOnce({ id: 55 });
    renderBook();

    await screen.findByText("Riyadh Salon");
    fireEvent.change(screen.getByLabelText("Service"), { target: { value: "10" } });
    fireEvent.change(screen.getByLabelText("Staff"), { target: { value: "99" } });
    fireEvent.change(screen.getByLabelText("Date"), { target: { value: "2026-03-14" } });
    fireEvent.change(screen.getByLabelText("Time"), { target: { value: "10:30" } });
    fireEvent.click(screen.getByRole("button", { name: "Confirm booking" }));

    await waitFor(() => {
      expect(screen.getByText("Pay Page")).toBeInTheDocument();
    });
    expect(apiPost).toHaveBeenCalledWith(
      "/bookings/",
      expect.objectContaining({
        service: 10,
        staff: 99,
        start_time: "2026-03-14T10:30:00+03:00",
        end_time: expect.any(String),
      }),
      null
    );
    const payload = apiPost.mock.calls[0][1];
    const startMs = new Date(payload.start_time).getTime();
    const endMs = new Date(payload.end_time).getTime();
    expect(endMs - startMs).toBe(60 * 60 * 1000);
  });

  it("shows API error message", async () => {
    apiPost.mockRejectedValueOnce(new Error("Booking failed"));
    renderBook();

    await screen.findByText("Riyadh Salon");
    fireEvent.change(screen.getByLabelText("Service"), { target: { value: "10" } });
    fireEvent.change(screen.getByLabelText("Staff"), { target: { value: "99" } });
    fireEvent.change(screen.getByLabelText("Date"), { target: { value: "2026-03-14" } });
    fireEvent.change(screen.getByLabelText("Time"), { target: { value: "10:30" } });
    fireEvent.click(screen.getByRole("button", { name: "Confirm booking" }));

    await waitFor(() => {
      expect(screen.getByText("Booking failed")).toBeInTheDocument();
    });
  });
});
