import { describe, it, expect, beforeEach, vi } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import { TaskStatus, TaskPriority, type Task } from "@mosaic/shared";
import { TasksWidget } from "../TasksWidget";
import { fetchTasks } from "@/lib/api/tasks";

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

const mockTasks: Task[] = [
  {
    id: "task-1",
    title: "API task one",
    description: null,
    status: TaskStatus.IN_PROGRESS,
    priority: TaskPriority.HIGH,
    dueDate: new Date("2026-02-03T09:00:00Z"),
    creatorId: "user-1",
    assigneeId: "user-1",
    workspaceId: "workspace-1",
    projectId: null,
    parentId: null,
    sortOrder: 0,
    metadata: {},
    completedAt: null,
    createdAt: new Date("2026-02-01T09:00:00Z"),
    updatedAt: new Date("2026-02-01T09:00:00Z"),
  },
  {
    id: "task-2",
    title: "API task two",
    description: null,
    status: TaskStatus.NOT_STARTED,
    priority: TaskPriority.MEDIUM,
    dueDate: new Date("2026-02-04T09:00:00Z"),
    creatorId: "user-1",
    assigneeId: "user-1",
    workspaceId: "workspace-1",
    projectId: null,
    parentId: null,
    sortOrder: 1,
    metadata: {},
    completedAt: null,
    createdAt: new Date("2026-02-01T09:00:00Z"),
    updatedAt: new Date("2026-02-01T09:00:00Z"),
  },
  {
    id: "task-3",
    title: "API task three",
    description: null,
    status: TaskStatus.COMPLETED,
    priority: TaskPriority.LOW,
    dueDate: new Date("2026-02-05T09:00:00Z"),
    creatorId: "user-1",
    assigneeId: "user-1",
    workspaceId: "workspace-1",
    projectId: null,
    parentId: null,
    sortOrder: 2,
    metadata: {},
    completedAt: new Date("2026-02-02T09:00:00Z"),
    createdAt: new Date("2026-02-01T09:00:00Z"),
    updatedAt: new Date("2026-02-02T09:00:00Z"),
  },
];

async function finishWidgetLoad(): Promise<void> {
  await waitFor(() => {
    expect(screen.queryByText("Loading tasks...")).not.toBeInTheDocument();
  });
}

describe("TasksWidget", (): void => {
  beforeEach((): void => {
    vi.clearAllMocks();
    vi.mocked(fetchTasks).mockResolvedValue(mockTasks);
  });

  it("renders loading state initially", (): void => {
    render(<TasksWidget id="tasks-1" />);

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

  it("fetches tasks and renders summary stats", async (): Promise<void> => {
    render(<TasksWidget id="tasks-1" />);

    await finishWidgetLoad();

    expect(fetchTasks).toHaveBeenCalledTimes(1);
    expect(screen.getByText("Total")).toBeInTheDocument();
    expect(screen.getByText("In Progress")).toBeInTheDocument();
    expect(screen.getByText("Done")).toBeInTheDocument();
    expect(screen.getByText("3")).toBeInTheDocument();
  });

  it("renders task rows from API response", async (): Promise<void> => {
    render(<TasksWidget id="tasks-1" />);

    await finishWidgetLoad();

    expect(screen.getByText("API task one")).toBeInTheDocument();
    expect(screen.getByText("API task two")).toBeInTheDocument();
    expect(screen.getByText("API task three")).toBeInTheDocument();
  });

  it("shows due date labels for each task", async (): Promise<void> => {
    render(<TasksWidget id="tasks-1" />);

    await finishWidgetLoad();

    expect(screen.getAllByText(/Due:/).length).toBe(3);
  });

  it("shows empty state when API returns no tasks", async (): Promise<void> => {
    vi.mocked(fetchTasks).mockResolvedValueOnce([]);

    render(<TasksWidget id="tasks-1" />);
    await finishWidgetLoad();

    expect(screen.getByText("No tasks yet")).toBeInTheDocument();
  });
});
