/**
 * TaskProgressWidget Component Tests
 */

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

const mockFetch = vi.fn();
global.fetch = mockFetch as unknown as typeof fetch;

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

  it("should render loading state initially", (): void => {
    mockFetch.mockImplementation(
      () =>
        new Promise(() => {
          // Never-resolving promise for loading state
        })
    );

    render(<TaskProgressWidget id="task-progress-1" />);

    expect(screen.getByText(/loading task progress/i)).toBeInTheDocument();
  });

  it("should display tasks after successful fetch", async (): Promise<void> => {
    const mockTasks = [
      {
        agentId: "agent-1",
        taskId: "TASK-001",
        status: "running",
        agentType: "worker",
        spawnedAt: new Date().toISOString(),
      },
      {
        agentId: "agent-2",
        taskId: "TASK-002",
        status: "completed",
        agentType: "reviewer",
        spawnedAt: new Date(Date.now() - 3600000).toISOString(),
        completedAt: new Date().toISOString(),
      },
    ];

    mockFetch.mockResolvedValueOnce({
      ok: true,
      json: () => Promise.resolve(mockTasks),
    } as unknown as Response);

    render(<TaskProgressWidget id="task-progress-1" />);

    await waitFor(() => {
      expect(screen.getByText("TASK-001")).toBeInTheDocument();
      expect(screen.getByText("TASK-002")).toBeInTheDocument();
    });

    // Check stats
    expect(screen.getByText("2")).toBeInTheDocument(); // Total
  });

  it("should display error state when fetch fails", async (): Promise<void> => {
    mockFetch.mockRejectedValueOnce(new Error("Network error"));

    render(<TaskProgressWidget id="task-progress-1" />);

    await waitFor(() => {
      expect(screen.getByText(/unable to reach orchestrator/i)).toBeInTheDocument();
    });
  });

  it("should display empty state when no tasks", async (): Promise<void> => {
    mockFetch.mockResolvedValueOnce({
      ok: true,
      json: () => Promise.resolve([]),
    } as unknown as Response);

    render(<TaskProgressWidget id="task-progress-1" />);

    await waitFor(() => {
      expect(screen.getByText(/no agent tasks in progress/i)).toBeInTheDocument();
    });
  });

  it("should show agent type badges", async (): Promise<void> => {
    const mockTasks = [
      {
        agentId: "agent-1",
        taskId: "TASK-001",
        status: "running",
        agentType: "worker",
        spawnedAt: new Date().toISOString(),
      },
      {
        agentId: "agent-2",
        taskId: "TASK-002",
        status: "running",
        agentType: "reviewer",
        spawnedAt: new Date().toISOString(),
      },
      {
        agentId: "agent-3",
        taskId: "TASK-003",
        status: "running",
        agentType: "tester",
        spawnedAt: new Date().toISOString(),
      },
    ];

    mockFetch.mockResolvedValueOnce({
      ok: true,
      json: () => Promise.resolve(mockTasks),
    } as unknown as Response);

    render(<TaskProgressWidget id="task-progress-1" />);

    await waitFor(() => {
      expect(screen.getByText("Worker")).toBeInTheDocument();
      expect(screen.getByText("Reviewer")).toBeInTheDocument();
      expect(screen.getByText("Tester")).toBeInTheDocument();
    });
  });

  it("should display error message for failed tasks", async (): Promise<void> => {
    const mockTasks = [
      {
        agentId: "agent-1",
        taskId: "TASK-FAIL",
        status: "failed",
        agentType: "worker",
        spawnedAt: new Date().toISOString(),
        error: "Build failed: type errors",
      },
    ];

    mockFetch.mockResolvedValueOnce({
      ok: true,
      json: () => Promise.resolve(mockTasks),
    } as unknown as Response);

    render(<TaskProgressWidget id="task-progress-1" />);

    await waitFor(() => {
      expect(screen.getByText("Build failed: type errors")).toBeInTheDocument();
    });
  });

  it("should sort active tasks before completed ones", async (): Promise<void> => {
    const mockTasks = [
      {
        agentId: "agent-completed",
        taskId: "COMPLETED-TASK",
        status: "completed",
        agentType: "worker",
        spawnedAt: new Date(Date.now() - 7200000).toISOString(),
        completedAt: new Date().toISOString(),
      },
      {
        agentId: "agent-running",
        taskId: "RUNNING-TASK",
        status: "running",
        agentType: "worker",
        spawnedAt: new Date().toISOString(),
      },
    ];

    mockFetch.mockResolvedValueOnce({
      ok: true,
      json: () => Promise.resolve(mockTasks),
    } as unknown as Response);

    render(<TaskProgressWidget id="task-progress-1" />);

    await waitFor(() => {
      const taskElements = screen.getAllByText(/TASK/);
      expect(taskElements).toHaveLength(2);
      // Running task should appear before completed
      expect(taskElements[0]?.textContent).toBe("RUNNING-TASK");
      expect(taskElements[1]?.textContent).toBe("COMPLETED-TASK");
    });
  });
});
