import { describe, it, expect, vi, beforeEach, beforeAll } from "vitest";
import { render, screen, waitFor, act } from "@testing-library/react";
import DashboardPage from "./page";
import * as layoutsApi from "@/lib/api/layouts";
import type { UserLayout, WidgetPlacement } from "@mosaic/shared";

// ResizeObserver is not available in jsdom
beforeAll((): void => {
  global.ResizeObserver = vi.fn().mockImplementation(() => ({
    observe: vi.fn(),
    unobserve: vi.fn(),
    disconnect: vi.fn(),
  }));
});

// Mock WidgetGrid to avoid react-grid-layout dependency in tests
vi.mock("@/components/widgets/WidgetGrid", () => ({
  WidgetGrid: ({
    layout,
    isEditing,
  }: {
    layout: WidgetPlacement[];
    isEditing?: boolean;
  }): React.JSX.Element => (
    <div data-testid="widget-grid" data-editing={isEditing}>
      {layout.map((item) => (
        <div key={item.i} data-testid={`widget-${item.i}`}>
          {item.i}
        </div>
      ))}
    </div>
  ),
}));

// Mock hooks
vi.mock("@/lib/hooks", () => ({
  useWorkspaceId: (): string | null => "ws-test-123",
}));

// Mock layout API
vi.mock("@/lib/api/layouts");

const mockExistingLayout: UserLayout = {
  id: "layout-1",
  workspaceId: "ws-test-123",
  userId: "user-1",
  name: "Default",
  isDefault: true,
  layout: [
    { i: "TasksWidget-default", x: 0, y: 0, w: 4, h: 2 },
    { i: "CalendarWidget-default", x: 4, y: 0, w: 4, h: 2 },
  ],
  metadata: {},
  createdAt: new Date("2026-01-01T00:00:00Z"),
  updatedAt: new Date("2026-01-01T00:00:00Z"),
};

describe("DashboardPage", (): void => {
  beforeEach((): void => {
    vi.clearAllMocks();
  });

  it("should render WidgetGrid with saved layout", async (): Promise<void> => {
    vi.mocked(layoutsApi.fetchDefaultLayout).mockResolvedValue(mockExistingLayout);

    render(<DashboardPage />);

    await waitFor((): void => {
      expect(screen.getByTestId("widget-grid")).toBeInTheDocument();
    });

    expect(screen.getByTestId("widget-TasksWidget-default")).toBeInTheDocument();
    expect(screen.getByTestId("widget-CalendarWidget-default")).toBeInTheDocument();
  });

  it("should create default layout when none exists", async (): Promise<void> => {
    vi.mocked(layoutsApi.fetchDefaultLayout).mockResolvedValue(null);
    vi.mocked(layoutsApi.createLayout).mockResolvedValue({
      ...mockExistingLayout,
      layout: [{ i: "TasksWidget-default", x: 0, y: 0, w: 4, h: 2 }],
    });

    render(<DashboardPage />);

    await waitFor((): void => {
      expect(layoutsApi.createLayout).toHaveBeenCalledWith("ws-test-123", {
        name: "Default",
        isDefault: true,
        layout: expect.arrayContaining([
          expect.objectContaining({ i: "TasksWidget-default" }),
        ]) as WidgetPlacement[],
      });
    });
  });

  it("should show loading spinner initially", (): void => {
    // Never-resolving promise to test loading state
    vi.mocked(layoutsApi.fetchDefaultLayout).mockReturnValue(
      // eslint-disable-next-line @typescript-eslint/no-empty-function -- intentionally never-resolving
      new Promise(() => {})
    );

    render(<DashboardPage />);

    expect(screen.getByText("Loading dashboard...")).toBeInTheDocument();
  });

  it("should fall back to default layout on API error", async (): Promise<void> => {
    vi.mocked(layoutsApi.fetchDefaultLayout).mockRejectedValue(new Error("Network error"));

    render(<DashboardPage />);

    await waitFor((): void => {
      expect(screen.getByTestId("widget-grid")).toBeInTheDocument();
    });
  });

  it("should render Dashboard heading", async (): Promise<void> => {
    vi.mocked(layoutsApi.fetchDefaultLayout).mockResolvedValue(mockExistingLayout);

    render(<DashboardPage />);

    await waitFor((): void => {
      expect(screen.getByText("Dashboard")).toBeInTheDocument();
    });
  });

  it("should render Edit Layout button", async (): Promise<void> => {
    vi.mocked(layoutsApi.fetchDefaultLayout).mockResolvedValue(mockExistingLayout);

    render(<DashboardPage />);

    await waitFor((): void => {
      expect(screen.getByText("Edit Layout")).toBeInTheDocument();
    });
  });

  it("should toggle edit mode on button click", async (): Promise<void> => {
    vi.mocked(layoutsApi.fetchDefaultLayout).mockResolvedValue(mockExistingLayout);

    render(<DashboardPage />);

    await waitFor((): void => {
      expect(screen.getByText("Edit Layout")).toBeInTheDocument();
    });

    act((): void => {
      screen.getByText("Edit Layout").click();
    });

    expect(screen.getByText("Done")).toBeInTheDocument();
    expect(screen.getByTestId("widget-grid").getAttribute("data-editing")).toBe("true");
  });
});
