import { describe, it, expect, vi, beforeEach } from "vitest";
import type { RouterContextProvider } from "react-router";
import { action } from "~/routes/api/draft.start";

const ctx = {} as unknown as RouterContextProvider;

vi.mock("~/database/context");
vi.mock("~/server/socket", () => ({
  getSocketIO: vi.fn(),
  scheduleDraftRoomClosure: vi.fn(),
}));
vi.mock("~/lib/auth.server", () => ({
  auth: { api: { getSession: vi.fn() } },
}));
vi.mock("~/models/commissioner", () => ({
  isCommissioner: vi.fn(),
}));
vi.mock("~/models/user", () => ({
  findUserById: vi.fn().mockResolvedValue(null),
  getUserDisplayName: vi.fn().mockReturnValue(null),
}));
vi.mock("~/services/draft-autostart", () => ({
  startDraft: vi.fn().mockResolvedValue({ success: true }),
}));

// ── Fixtures ─────────────────────────────────────────────────────────────────

const SEASON_ID = "season-1";
const COMMISSIONER_ID = "commissioner-user-1";

function makeSeason(overrides: Record<string, unknown> = {}) {
  return {
    id: SEASON_ID,
    leagueId: "league-1",
    status: "pre_draft",
    draftInitialTime: 120,
    draftIncrementTime: 30,
    draftTimerMode: "chess_clock",
    ...overrides,
  };
}

function makeRequest() {
  const formData = new FormData();
  formData.append("seasonId", SEASON_ID);
  return new Request("http://localhost/api/draft/start", {
    method: "POST",
    body: formData,
  });
}

// ── Tests ─────────────────────────────────────────────────────────────────────

describe("draft.start action", () => {
  let mockDb: any;
  let mockSocketIO: any;

  beforeEach(async () => {
    vi.clearAllMocks();

    const { auth } = await import("~/lib/auth.server");
    vi.mocked(auth.api.getSession).mockResolvedValue({ user: { id: COMMISSIONER_ID } } as any);

    const { isCommissioner } = await import("~/models/commissioner");
    vi.mocked(isCommissioner).mockResolvedValue(true);

    mockSocketIO = { to: vi.fn().mockReturnThis(), emit: vi.fn() };
    const socketModule = await import("~/server/socket");
    vi.mocked(socketModule.getSocketIO).mockReturnValue(mockSocketIO);

    mockDb = {
      query: {
        seasons: { findFirst: vi.fn() },
      },
    };

    const { database } = await import("~/database/context");
    vi.mocked(database).mockReturnValue(mockDb);

    const { startDraft } = await import("~/services/draft-autostart");
    vi.mocked(startDraft).mockResolvedValue({ success: true });
  });

  it("returns 401 when not authenticated", async () => {
    const { auth } = await import("~/lib/auth.server");
    vi.mocked(auth.api.getSession).mockResolvedValue(null);

    const res = await action({ request: makeRequest(), params: {}, context: ctx });
    expect(res.status).toBe(401);
  });

  it("returns 404 when season not found", async () => {
    mockDb.query.seasons.findFirst.mockResolvedValue(null);

    const res = await action({ request: makeRequest(), params: {}, context: ctx });
    expect(res.status).toBe(404);
  });

  it("returns 403 when user is not a commissioner", async () => {
    mockDb.query.seasons.findFirst.mockResolvedValue(makeSeason());
    const { isCommissioner } = await import("~/models/commissioner");
    vi.mocked(isCommissioner).mockResolvedValue(false);

    const res = await action({ request: makeRequest(), params: {}, context: ctx });
    expect(res.status).toBe(403);
  });

  it("calls startDraft and returns 200 on success", async () => {
    mockDb.query.seasons.findFirst.mockResolvedValue(makeSeason());

    const res = await action({ request: makeRequest(), params: {}, context: ctx });

    const { startDraft } = await import("~/services/draft-autostart");
    expect(vi.mocked(startDraft)).toHaveBeenCalledWith(
      expect.objectContaining({ seasonId: SEASON_ID })
    );
    expect(res.status).toBe(200);
  });

  it("returns 400 when startDraft reports draft already started", async () => {
    mockDb.query.seasons.findFirst.mockResolvedValue(makeSeason());
    const { startDraft } = await import("~/services/draft-autostart");
    vi.mocked(startDraft).mockResolvedValue({ success: false, error: "Draft already started or completed" });

    const res = await action({ request: makeRequest(), params: {}, context: ctx });
    expect(res.status).toBe(400);
  });

  it("returns 400 when startDraft reports no draft slots", async () => {
    mockDb.query.seasons.findFirst.mockResolvedValue(makeSeason());
    const { startDraft } = await import("~/services/draft-autostart");
    vi.mocked(startDraft).mockResolvedValue({ success: false, error: "No draft slots found for this season" });

    const res = await action({ request: makeRequest(), params: {}, context: ctx });
    expect(res.status).toBe(400);
  });
});
