import type { ReactElement, ReactNode } from "react";
import type { TeamRecord } from "@/lib/api/teams";

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 { createTeam, deleteTeam, fetchTeams, updateTeam } from "@/lib/api/teams";
import { fetchUserWorkspaces } from "@/lib/api/workspaces";

import TeamsSettingsPage 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/teams", () => ({
  fetchTeams: vi.fn(),
  createTeam: vi.fn(),
  updateTeam: vi.fn(),
  deleteTeam: vi.fn(),
}));

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

const fetchTeamsMock = vi.mocked(fetchTeams);
const createTeamMock = vi.mocked(createTeam);
const updateTeamMock = vi.mocked(updateTeam);
const deleteTeamMock = vi.mocked(deleteTeam);
const fetchUserWorkspacesMock = vi.mocked(fetchUserWorkspaces);

const baseTeam: TeamRecord = {
  id: "team-1",
  workspaceId: "workspace-1",
  name: "Platform Team",
  description: "Owns platform services",
  metadata: {},
  createdAt: "2026-02-01T00:00:00.000Z",
  updatedAt: "2026-02-01T00:00:00.000Z",
  _count: {
    members: 3,
  },
};

describe("TeamsSettingsPage", () => {
  beforeEach(() => {
    vi.clearAllMocks();
    fetchTeamsMock.mockResolvedValue([]);
    fetchUserWorkspacesMock.mockResolvedValue([
      {
        id: "workspace-1",
        name: "Personal Workspace",
        ownerId: "owner-1",
        role: WorkspaceMemberRole.OWNER,
        createdAt: "2026-01-01T00:00:00.000Z",
      },
    ]);
  });

  it("shows access denied to non-admin users", async () => {
    fetchUserWorkspacesMock.mockResolvedValueOnce([
      {
        id: "workspace-1",
        name: "Personal Workspace",
        ownerId: "owner-1",
        role: WorkspaceMemberRole.MEMBER,
        createdAt: "2026-01-01T00:00:00.000Z",
      },
    ]);

    render(<TeamsSettingsPage />);

    expect(await screen.findByText("Access Denied")).toBeInTheDocument();
    expect(fetchTeamsMock).not.toHaveBeenCalled();
  });

  it("loads and renders teams from the API", async () => {
    fetchTeamsMock.mockResolvedValue([baseTeam]);

    render(<TeamsSettingsPage />);

    expect(await screen.findByText("Team Directory")).toBeInTheDocument();
    expect(screen.getByText("Platform Team")).toBeInTheDocument();
    expect(fetchTeamsMock).toHaveBeenCalledTimes(1);
  });

  it("shows empty state when the API returns no teams", async () => {
    fetchTeamsMock.mockResolvedValue([]);

    render(<TeamsSettingsPage />);

    expect(await screen.findByText("No Teams Yet")).toBeInTheDocument();
    expect(screen.getByText("Create the first team to get started.")).toBeInTheDocument();
  });

  it("shows error state and does not show empty state", async () => {
    fetchTeamsMock.mockRejectedValue(new Error("Unable to load teams"));

    render(<TeamsSettingsPage />);

    expect(await screen.findByText("Unable to load teams")).toBeInTheDocument();
  });

  it("creates a team from the create dialog", async () => {
    const user = userEvent.setup();
    fetchTeamsMock.mockResolvedValue([baseTeam]);
    createTeamMock.mockResolvedValue({
      ...baseTeam,
      id: "team-2",
      name: "Design Team",
      description: "Owns design quality",
    });

    render(<TeamsSettingsPage />);

    expect(await screen.findByText("Platform Team")).toBeInTheDocument();

    const triggerButton = screen.getByRole("button", { name: "Create Team" });
    await user.click(triggerButton);

    await user.type(screen.getByLabelText("Name"), "Design Team");
    await user.type(screen.getByLabelText("Description"), "Owns design quality");

    const submitButton = screen.getAllByRole("button", { name: "Create Team" })[1];
    if (!submitButton) {
      throw new Error("Expected create-team submit button to be rendered");
    }
    await user.click(submitButton);

    await waitFor(() => {
      expect(createTeamMock).toHaveBeenCalledWith({
        name: "Design Team",
        description: "Owns design quality",
      });
    });
  });

  it("opens team details and updates name", async () => {
    const user = userEvent.setup();
    fetchTeamsMock.mockResolvedValue([baseTeam]);
    updateTeamMock.mockResolvedValue({
      ...baseTeam,
      name: "Platform Engineering",
    });

    render(<TeamsSettingsPage />);

    expect(await screen.findByText("Platform Team")).toBeInTheDocument();

    await user.click(screen.getByText("Platform Team"));

    const nameInput = await screen.findByLabelText("Name");
    await user.clear(nameInput);
    await user.type(nameInput, "Platform Engineering");
    await user.click(screen.getByRole("button", { name: "Save Changes" }));

    await waitFor(() => {
      expect(updateTeamMock).toHaveBeenCalledWith("team-1", {
        name: "Platform Engineering",
      });
    });
  });

  it("deletes a team from the confirmation dialog", async () => {
    const user = userEvent.setup();
    fetchTeamsMock.mockResolvedValue([baseTeam]);
    deleteTeamMock.mockResolvedValue();

    render(<TeamsSettingsPage />);

    expect(await screen.findByText("Platform Team")).toBeInTheDocument();

    await user.click(screen.getByRole("button", { name: "Delete" }));
    await user.click(screen.getByRole("button", { name: "Delete Team" }));

    await waitFor(() => {
      expect(deleteTeamMock).toHaveBeenCalledWith("team-1");
    });
  });
});
