import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

import { ServerCard } from "@/components/servers/ServerCard";
import type { Server } from "@/hooks/useServers";
import {
  useStartServer,
  useStopServer,
  useRestartServer,
} from "@/hooks/useServers";

vi.mock("@/hooks/useServers", () => ({
  useStartServer: vi.fn(),
  useStopServer: vi.fn(),
  useRestartServer: vi.fn(),
}));

const mockMutation = (resolve?: boolean) => ({
  mutateAsync: vi.fn(() => (resolve === false ? Promise.reject(new Error("fail")) : Promise.resolve())),
  isPending: false,
});

function renderCard(server: Partial<Server> = {}) {
  const fullServer: Server = {
    id: 1,
    name: "Test Arma3",
    game_type: "arma3",
    status: "running",
    port: 2302,
    max_players: 64,
    current_players: 32,
    restart_count: 3,
    auto_restart: true,
    created_at: "2026-01-01T00:00:00Z",
    ...server,
  };

  const queryClient = new QueryClient({
    defaultOptions: { queries: { retry: false } },
  });

  return {
    user: userEvent.setup(),
    ...render(
      <QueryClientProvider client={queryClient}>
        <ServerCard server={fullServer} />
      </QueryClientProvider>,
    ),
  };
}

describe("ServerCard", () => {
  beforeEach(() => {
    vi.mocked(useStartServer).mockReturnValue(mockMutation() as unknown as ReturnType<typeof useStartServer>);
    vi.mocked(useStopServer).mockReturnValue(mockMutation() as unknown as ReturnType<typeof useStopServer>);
    vi.mocked(useRestartServer).mockReturnValue(mockMutation() as unknown as ReturnType<typeof useRestartServer>);
  });

  it("should render server name and game type", () => {
    renderCard();
    expect(screen.getByText("Test Arma3")).toBeInTheDocument();
    expect(screen.getByText("arma3")).toBeInTheDocument();
  });

  it("should display player count", () => {
    renderCard();
    expect(screen.getByText("32/64")).toBeInTheDocument();
  });

  it("should display port number", () => {
    renderCard({ port: 2302 });
    expect(screen.getByText("2302")).toBeInTheDocument();
  });

  it("should display restart count", () => {
    renderCard({ restart_count: 3 });
    expect(screen.getByText("3")).toBeInTheDocument();
  });

  it("should show Stop button when server is running", () => {
    renderCard({ status: "running" });
    expect(screen.getByLabelText("Stop Test Arma3")).toBeInTheDocument();
  });

  it("should show Start button when server is stopped", () => {
    renderCard({ status: "stopped" });
    expect(screen.getByLabelText("Start Test Arma3")).toBeInTheDocument();
  });

  it("should not show Start button when server is running", () => {
    renderCard({ status: "running" });
    expect(screen.queryByLabelText(/Start Test Arma3/)).not.toBeInTheDocument();
  });

  it("should show Restart button when server is running", () => {
    renderCard({ status: "running" });
    expect(screen.getByLabelText("Restart Test Arma3")).toBeInTheDocument();
  });

  it("should disable Stop button when server is starting", () => {
    renderCard({ status: "starting" });
    const stopBtn = screen.getByLabelText("Stop Test Arma3");
    expect(stopBtn).toBeDisabled();
  });

  it("should call startServer on Start click", async () => {
    const startMutation = mockMutation();
    vi.mocked(useStartServer).mockReturnValue(startMutation as unknown as ReturnType<typeof useStartServer>);

    const { user } = renderCard({ status: "stopped" });
    await user.click(screen.getByLabelText("Start Test Arma3"));
    expect(startMutation.mutateAsync).toHaveBeenCalledWith(1);
  });
});