import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, within, waitFor } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import { App } from "../App";


// Mock fetch to return appropriate responses based on URL
beforeEach(() => {
  localStorage.clear();
  global.fetch = vi.fn((url: string) => {
    if (url === "/api/dev/config") {
      return Promise.resolve({
        ok: true,
        json: async () => ({ authDisabled: false }),
      } as Response);
    }
    if (url === "/api/branding") {
      return Promise.resolve({
        ok: true,
        json: async () => ({
          businessName: "GroomBook",
          primaryColor: "#4f8a6f",
          accentColor: "#8b7355",
          logoBase64: null,
          logoMimeType: null,
        }),
      } as Response);
    }
    return Promise.resolve({
      ok: true,
      json: async () => [],
    } as Response);
  }) as unknown as typeof fetch;
});

async function renderApp(route = "/admin") {
  render(
    <MemoryRouter initialEntries={[route]}>
      <App />
    </MemoryRouter>
  );
  // Wait for the config fetch to resolve
  const nav = await screen.findByRole("navigation");
  return nav;
}

describe("App navigation", () => {
  // Use authDisabled=true (dev mode) so nav renders without needing Better Auth useSession() mock
  beforeEach(() => {
    localStorage.setItem("dev-user", JSON.stringify({ type: "staff", id: "s1", name: "Sarah" }));
    global.fetch = vi.fn((url: string) => {
      if (url === "/api/dev/config") {
        return Promise.resolve({
          ok: true,
          json: async () => ({ authDisabled: true }),
        } as Response);
      }
      if (url === "/api/branding") {
        return Promise.resolve({
          ok: true,
          json: async () => ({
            businessName: "GroomBook",
            primaryColor: "#4f8a6f",
            accentColor: "#8b7355",
            logoBase64: null,
            logoMimeType: null,
          }),
        } as Response);
      }
      return Promise.resolve({ ok: true, json: async () => [] } as Response);
    }) as unknown as typeof fetch;
  });

  it("renders the Groom Book brand", async () => {
    const nav = await renderApp();
    expect(
      within(nav).getByText((_, el) => el?.tagName === "STRONG" && /Groom\s*Book/.test(el.textContent ?? ""))
    ).toBeInTheDocument();
  });

  it("renders the Book CTA button", async () => {
    const nav = await renderApp();
    expect(within(nav).getByRole("link", { name: "Book" })).toBeInTheDocument();
  });

  it("renders all primary nav links", async () => {
    const nav = await renderApp();
    const expectedLinks = [
      "Appointments",
      "Clients",
      "Services",
      "Staff",
      "Invoices",
      "Group Bookings",
      "Reports",
    ];
    expectedLinks.forEach((label) => {
      expect(within(nav).getByText(label)).toBeInTheDocument();
    });
  });

  it("highlights the active route link", async () => {
    const nav = await renderApp("/admin/clients");
    const clientsLink = within(nav).getByText("Clients");
    // Active links use fontWeight 600
    expect(clientsLink).toHaveStyle({ fontWeight: "600" });
  });

  it("renders customer portal at root", async () => {
    render(
      <MemoryRouter initialEntries={["/"]}>
        <App />
      </MemoryRouter>
    );
    // Customer portal should render at root - no admin nav present
    await waitFor(() => {
      expect(
        screen.queryByText((_, el) => el?.tagName === "STRONG" && /Groom\s*Book/.test(el.textContent ?? ""))
      ).not.toBeInTheDocument();
    });
  });
});

describe("GRO-2011 — setup/status fetch for unauthenticated users", () => {
  it("calls /api/setup/status for unauthenticated users so needsSetup is never stuck null", async () => {
    const setupStatusCalls: string[] = [];

    global.fetch = vi.fn((url: string) => {
      if (url === "/api/dev/config") {
        return Promise.resolve({
          ok: true,
          json: async () => ({ authDisabled: false }),
        } as Response);
      }
      if (url === "/api/auth/get-session") {
        // Better Auth returns 200 with null session for unauthenticated users.
        return Promise.resolve({
          ok: true,
          json: async () => null,
        } as unknown as Response);
      }
      if (url === "/api/setup/status") {
        setupStatusCalls.push(url);
        return Promise.resolve({
          ok: true,
          json: async () => ({ needsSetup: false }),
        } as Response);
      }
      if (url === "/api/branding") {
        return Promise.resolve({
          ok: true,
          json: async () => ({
            businessName: "GroomBook",
            primaryColor: "#4f8a6f",
            accentColor: "#8b7355",
            logoBase64: null,
            logoMimeType: null,
          }),
        } as Response);
      }
      return Promise.resolve({ ok: true, json: async () => [] } as Response);
    }) as unknown as typeof fetch;

    render(
      <MemoryRouter initialEntries={["/login"]}>
        <App />
      </MemoryRouter>
    );

    // The login page should be rendered for the unauthenticated user.
    await screen.findByText("Sign in to continue");

    // Crucially, /api/setup/status must be called even when the user is unauthenticated —
    // otherwise `needsSetup` stays null and a later code path can short-circuit to a
    // blank page (GRO-2011).
    await waitFor(() => {
      expect(setupStatusCalls.length).toBeGreaterThanOrEqual(1);
    });
    expect(setupStatusCalls[0]).toBe("/api/setup/status");
  });
});

describe("Dev login selector", () => {
  it("redirects to /login when auth is disabled and no user selected", async () => {
    global.fetch = vi.fn((url: string) => {
      if (url === "/api/dev/config") {
        return Promise.resolve({
          ok: true,
          json: async () => ({ authDisabled: true }),
        } as Response);
      }
      if (url === "/api/dev/users") {
        return Promise.resolve({
          ok: true,
          json: async () => ({
            staff: [{ id: "s1", name: "Sarah", email: "sarah@test.com", role: "groomer" }],
            clients: [{ id: "c1", name: "Client A", email: "a@test.com", petCount: 2 }],
          }),
        } as Response);
      }
      if (url === "/api/branding") {
        return Promise.resolve({
          ok: true,
          json: async () => ({
            businessName: "GroomBook",
            primaryColor: "#4f8a6f",
            accentColor: "#8b7355",
            logoBase64: null,
            logoMimeType: null,
          }),
        } as Response);
      }
      if (url === "/api/auth/get-session") {
        return Promise.resolve({
          ok: true,
          json: async () => ({ user: null }),
        } as Response);
      }
      return Promise.resolve({ ok: true, json: async () => [] } as Response);
    }) as unknown as typeof fetch;

    render(
      <MemoryRouter initialEntries={["/admin"]}>
        <App />
      </MemoryRouter>
    );

    // Should redirect to login selector and show dev login UI
    await screen.findByText("Dev Login Selector");
    expect(screen.getByText("Sarah")).toBeInTheDocument();
    expect(screen.getByText("Client A")).toBeInTheDocument();
  });

  it("does not redirect when a dev user is already selected", async () => {
    localStorage.setItem("dev-user", JSON.stringify({ type: "staff", id: "s1", name: "Sarah" }));

    global.fetch = vi.fn((url: string) => {
      if (url === "/api/dev/config") {
        return Promise.resolve({
          ok: true,
          json: async () => ({ authDisabled: true }),
        } as Response);
      }
      if (url === "/api/branding") {
        return Promise.resolve({
          ok: true,
          json: async () => ({
            businessName: "GroomBook",
            primaryColor: "#4f8a6f",
            accentColor: "#8b7355",
            logoBase64: null,
            logoMimeType: null,
          }),
        } as Response);
      }
      return Promise.resolve({ ok: true, json: async () => [] } as Response);
    }) as unknown as typeof fetch;

    render(
      <MemoryRouter initialEntries={["/admin"]}>
        <App />
      </MemoryRouter>
    );

    // Should show admin nav, not login selector
    const nav = await screen.findByRole("navigation");
    expect(
      within(nav).getByText((_, el) => el?.tagName === "STRONG" && /Groom\s*Book/.test(el.textContent ?? ""))
    ).toBeInTheDocument();
  });
});
