import { beforeEach, describe, expect, it, vi } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import type {
  ButtonHTMLAttributes,
  InputHTMLAttributes,
  LabelHTMLAttributes,
  ReactNode,
} from "react";

interface MockButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
  children: ReactNode;
}

interface MockInputProps extends InputHTMLAttributes<HTMLInputElement> {
  children?: ReactNode;
}

interface MockLabelProps extends LabelHTMLAttributes<HTMLLabelElement> {
  children: ReactNode;
}

interface MockSession {
  id: string;
  providerId: string;
  providerType: string;
  status: "active" | "paused";
  createdAt: Date;
  updatedAt: Date;
}

const mockApiPost = vi.fn<(endpoint: string, body?: unknown) => Promise<{ message: string }>>();

vi.mock("@/lib/api/client", () => ({
  apiPost: (endpoint: string, body?: unknown): Promise<{ message: string }> =>
    mockApiPost(endpoint, body),
}));

vi.mock("@/components/ui/button", () => ({
  Button: ({ children, ...props }: MockButtonProps): React.JSX.Element => (
    <button {...props}>{children}</button>
  ),
}));

vi.mock("@/components/ui/input", () => ({
  Input: ({ ...props }: MockInputProps): React.JSX.Element => <input {...props} />,
}));

vi.mock("@/components/ui/label", () => ({
  Label: ({ children, ...props }: MockLabelProps): React.JSX.Element => (
    <label {...props}>{children}</label>
  ),
}));

import { KillAllDialog } from "./KillAllDialog";

function makeSession(overrides: Partial<MockSession>): MockSession {
  return {
    id: "session-1",
    providerId: "internal",
    providerType: "internal",
    status: "active",
    createdAt: new Date("2026-03-07T10:00:00.000Z"),
    updatedAt: new Date("2026-03-07T10:01:00.000Z"),
    ...overrides,
  };
}

describe("KillAllDialog", (): void => {
  beforeEach((): void => {
    vi.clearAllMocks();
    mockApiPost.mockResolvedValue({ message: "killed" });
  });

  it("renders trigger button and requires exact confirmation text", async (): Promise<void> => {
    const user = userEvent.setup();

    render(<KillAllDialog sessions={[makeSession({})]} />);

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

    const confirmInput = screen.getByLabelText("Type KILL ALL to confirm");
    const confirmButton = screen.getByRole("button", { name: "Kill All Agents" });

    expect(confirmButton).toBeDisabled();

    await user.type(confirmInput, "kill all");
    expect(confirmButton).toBeDisabled();

    await user.clear(confirmInput);
    await user.type(confirmInput, "KILL ALL");

    expect(confirmButton).toBeEnabled();
  });

  it("kills only internal sessions by default and invokes completion callback", async (): Promise<void> => {
    const onComplete = vi.fn<() => void>();
    const user = userEvent.setup();

    render(
      <KillAllDialog
        sessions={[
          makeSession({ id: "internal-1", providerType: "internal" }),
          makeSession({ id: "external-1", providerType: "external" }),
        ]}
        onComplete={onComplete}
      />
    );

    await user.click(screen.getByRole("button", { name: "Kill All" }));
    await user.type(screen.getByLabelText("Type KILL ALL to confirm"), "KILL ALL");
    await user.click(screen.getByRole("button", { name: "Kill All Agents" }));

    await waitFor((): void => {
      expect(mockApiPost).toHaveBeenCalledWith("/api/mission-control/sessions/internal-1/kill", {
        force: true,
      });
    });

    expect(mockApiPost).not.toHaveBeenCalledWith("/api/mission-control/sessions/external-1/kill", {
      force: true,
    });
    expect(onComplete).toHaveBeenCalledTimes(1);
  });

  it("kills all providers when all scope is selected", async (): Promise<void> => {
    const user = userEvent.setup();

    render(
      <KillAllDialog
        sessions={[
          makeSession({ id: "internal-2", providerType: "internal" }),
          makeSession({ id: "external-2", providerType: "external" }),
        ]}
      />
    );

    await user.click(screen.getByRole("button", { name: "Kill All" }));
    await user.click(screen.getByRole("radio", { name: /All providers \(2\)/ }));
    await user.type(screen.getByLabelText("Type KILL ALL to confirm"), "KILL ALL");
    await user.click(screen.getByRole("button", { name: "Kill All Agents" }));

    await waitFor((): void => {
      expect(mockApiPost).toHaveBeenCalledWith("/api/mission-control/sessions/internal-2/kill", {
        force: true,
      });
      expect(mockApiPost).toHaveBeenCalledWith("/api/mission-control/sessions/external-2/kill", {
        force: true,
      });
    });
  });

  it("shows empty-scope warning when internal sessions are unavailable", async (): Promise<void> => {
    const user = userEvent.setup();

    render(
      <KillAllDialog
        sessions={[
          makeSession({ id: "external-only", providerId: "ext", providerType: "external" }),
        ]}
      />
    );

    await user.click(screen.getByRole("button", { name: "Kill All" }));
    await user.type(screen.getByLabelText("Type KILL ALL to confirm"), "KILL ALL");

    expect(screen.getByText("No sessions in the selected scope.")).toBeInTheDocument();
    expect(screen.getByRole("button", { name: "Kill All Agents" })).toBeDisabled();
  });
});
