import type { UserWorkspace, WorkspaceMemberEntry } from "@/lib/api/workspaces";
import type { ReactElement, ReactNode } from "react";

import { WorkspaceMemberRole } from "@mosaic/shared";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { beforeEach, describe, expect, it, vi } from "vitest";

import { createWorkspace, fetchUserWorkspaces, fetchWorkspaceMembers } from "@/lib/api/workspaces";
import WorkspacesPage from "./page";

vi.mock("next/link", () => ({
  default: function LinkMock({
    children,
    href,
  }: {
    children: ReactNode;
    href: string;
  }): ReactElement {
    return <a href={href}>{children}</a>;
  },
}));

vi.mock("@/lib/api/workspaces", () => ({
  fetchUserWorkspaces: vi.fn(),
  createWorkspace: vi.fn(),
  fetchWorkspaceMembers: vi.fn(),
  addWorkspaceMember: vi.fn(),
  removeWorkspaceMember: vi.fn(),
}));

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

const fetchUserWorkspacesMock = vi.mocked(fetchUserWorkspaces);
const createWorkspaceMock = vi.mocked(createWorkspace);
const fetchWorkspaceMembersMock = vi.mocked(fetchWorkspaceMembers);

const workspaceA: UserWorkspace = {
  id: "workspace-1",
  name: "Personal Workspace",
  ownerId: "owner-1",
  role: WorkspaceMemberRole.OWNER,
  createdAt: "2026-01-01T00:00:00.000Z",
};

const workspaceB: UserWorkspace = {
  id: "workspace-2",
  name: "Client Workspace",
  ownerId: "owner-2",
  role: WorkspaceMemberRole.ADMIN,
  createdAt: "2026-01-02T00:00:00.000Z",
};

const membersA: WorkspaceMemberEntry[] = [
  {
    workspaceId: "workspace-1",
    userId: "user-a",
    role: WorkspaceMemberRole.OWNER,
    joinedAt: "2026-01-03T00:00:00.000Z",
    user: {
      id: "user-a",
      email: "alice@example.com",
      name: "Alice",
      image: null,
    },
  },
];

const membersB: WorkspaceMemberEntry[] = [
  {
    workspaceId: "workspace-2",
    userId: "user-b",
    role: WorkspaceMemberRole.MEMBER,
    joinedAt: "2026-01-04T00:00:00.000Z",
    user: {
      id: "user-b",
      email: "bob@example.com",
      name: "Bob",
      image: null,
    },
  },
];

describe("WorkspacesPage", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("loads workspaces and fetches members for the first workspace", async () => {
    fetchUserWorkspacesMock.mockResolvedValue([workspaceA, workspaceB]);
    fetchWorkspaceMembersMock.mockResolvedValue(membersA);

    render(<WorkspacesPage />);

    expect(await screen.findByText("Your Workspaces (2)")).toBeInTheDocument();
    expect(await screen.findByText("Personal Workspace Members")).toBeInTheDocument();

    await waitFor(() => {
      expect(fetchWorkspaceMembersMock).toHaveBeenCalledWith("workspace-1");
    });

    expect(screen.getByText("alice@example.com")).toBeInTheDocument();
  });

  it("switches selected workspace and reloads member list", async () => {
    fetchUserWorkspacesMock.mockResolvedValue([workspaceA, workspaceB]);
    fetchWorkspaceMembersMock.mockResolvedValueOnce(membersA).mockResolvedValueOnce(membersB);

    const user = userEvent.setup();
    render(<WorkspacesPage />);

    expect(await screen.findByText("Personal Workspace Members")).toBeInTheDocument();

    await user.click(screen.getByRole("button", { name: /client workspace/i }));

    await waitFor(() => {
      expect(fetchWorkspaceMembersMock).toHaveBeenLastCalledWith("workspace-2");
    });

    expect(await screen.findByText("Client Workspace Members")).toBeInTheDocument();
    expect(screen.getByText("bob@example.com")).toBeInTheDocument();
  });

  it("creates a workspace and refreshes the list", async () => {
    fetchUserWorkspacesMock
      .mockResolvedValueOnce([workspaceA])
      .mockResolvedValueOnce([workspaceA, workspaceB]);
    fetchWorkspaceMembersMock.mockResolvedValue(membersA);
    createWorkspaceMock.mockResolvedValue({
      id: "workspace-2",
      name: "Client Workspace",
      ownerId: "owner-2",
      settings: {},
      createdAt: "2026-01-02T00:00:00.000Z",
      updatedAt: "2026-01-02T00:00:00.000Z",
      memberCount: 1,
    });

    const user = userEvent.setup();
    render(<WorkspacesPage />);

    expect(await screen.findByText("Your Workspaces (1)")).toBeInTheDocument();

    await user.type(screen.getByPlaceholderText("Enter workspace name..."), "Client Workspace");
    await user.click(screen.getByRole("button", { name: "Create Workspace" }));

    await waitFor(() => {
      expect(createWorkspaceMock).toHaveBeenCalledWith({ name: "Client Workspace" });
    });

    await waitFor(() => {
      expect(fetchUserWorkspacesMock).toHaveBeenCalledTimes(2);
    });

    expect(await screen.findByText("Your Workspaces (2)")).toBeInTheDocument();
  });
});
