import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import DashboardLayout from "@/components/DashboardLayout";

const { authState } = vi.hoisted(() => ({
  authState: {
    authInfo: {
      token: "session-token",
      name: "أحمد المستثمر",
    } as { token: string; name: string } | null,
    _hydrated: true,
  },
}));

vi.mock("@/components/AuthGuard", () => ({
  default: ({ children }: { children: React.ReactNode }) => <>{children}</>,
}));

vi.mock("@/components/Sidebar", () => ({
  default: () => <div data-testid="sidebar" />,
}));

vi.mock("@/components/FcmInit", () => ({
  default: () => null,
}));

vi.mock("@/lib/auth/store", () => ({
  useAuthStore: Object.assign(
    (selector: (state: typeof authState) => unknown) => selector(authState),
    {
      getState: () => authState,
    },
  ),
}));

vi.mock("@/lib/api", () => ({
  apiFetch: vi.fn(),
}));

import { apiFetch } from "@/lib/api";

function mockCountResponse(count: number) {
  vi.mocked(apiFetch).mockResolvedValue({
    key: "success",
    data: { count },
    msg: "",
  });
}

describe("DashboardLayout", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    authState.authInfo = {
      token: "session-token",
      name: "أحمد المستثمر",
    };
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  it("fetches the unread notification count when the user is authenticated", async () => {
    mockCountResponse(3);

    render(
      <DashboardLayout title="الرئيسية" subtitle="نظرة عامة">
        <p>محتوى الصفحة</p>
      </DashboardLayout>,
    );

    await waitFor(() => {
      expect(apiFetch).toHaveBeenCalledWith("/provider/count-notifications", {
        method: "GET",
      });
    });

    expect(await screen.findByText("3")).toBeInTheDocument();
    expect(screen.getByText("أحمد المستثمر 👋")).toBeInTheDocument();
    expect(screen.getByText("محتوى الصفحة")).toBeInTheDocument();
  });

  it("does not fetch the unread count when there is no auth token", async () => {
    authState.authInfo = null;

    render(
      <DashboardLayout title="الرئيسية">
        <p>محتوى الصفحة</p>
      </DashboardLayout>,
    );

    expect(apiFetch).not.toHaveBeenCalled();
    expect(screen.getByText("مرحباً بك 👋")).toBeInTheDocument();
  });

  it("refetches the unread count when bb_notifications_updated fires", async () => {
    mockCountResponse(2);

    render(
      <DashboardLayout title="الرئيسية">
        <p>محتوى الصفحة</p>
      </DashboardLayout>,
    );

    await waitFor(() => {
      expect(apiFetch).toHaveBeenCalledTimes(1);
    });

    mockCountResponse(7);
    globalThis.dispatchEvent(
      new CustomEvent("bb_notifications_updated", { detail: { count: 7 } }),
    );

    await waitFor(() => {
      expect(apiFetch).toHaveBeenCalledTimes(1);
    });
    expect(await screen.findByText("7")).toBeInTheDocument();
  });

  it("caps the unread badge at +99 for large counts", async () => {
    mockCountResponse(150);

    render(
      <DashboardLayout title="الرئيسية">
        <p>محتوى الصفحة</p>
      </DashboardLayout>,
    );

    expect(await screen.findByText("+99")).toBeInTheDocument();
  });

  it("hides the unread badge when the count is zero", async () => {
    mockCountResponse(0);

    render(
      <DashboardLayout title="الرئيسية">
        <p>محتوى الصفحة</p>
      </DashboardLayout>,
    );

    await waitFor(() => {
      expect(apiFetch).toHaveBeenCalledTimes(1);
    });

    expect(screen.queryByText("0")).not.toBeInTheDocument();
  });

  it("does not create an unread badge when the response omits count", async () => {
    vi.mocked(apiFetch).mockResolvedValue({
      key: "success",
      data: {},
      msg: "",
    });

    render(
      <DashboardLayout title="الرئيسية">
        <p>محتوى الصفحة</p>
      </DashboardLayout>,
    );

    await waitFor(() => expect(apiFetch).toHaveBeenCalledTimes(1));
    expect(screen.queryByText(/^\+?\d+$/)).not.toBeInTheDocument();
  });
});
