import { describe, it, expect, vi, beforeEach } from "vitest";

vi.mock("~/models/season-participant", () => ({
  findParticipantsBySportsSeasonId: vi.fn(),
  findParticipantByName: vi.fn(),
  createParticipant: vi.fn(),
  deleteParticipant: vi.fn(),
  updateParticipant: vi.fn(),
}));

vi.mock("~/models/sports-season", () => ({
  findSportsSeasonById: vi.fn(),
}));

vi.mock("~/lib/logger", () => ({
  logger: { error: vi.fn() },
}));

import {
  findParticipantByName,
  updateParticipant,
} from "~/models/season-participant";
import { action } from "~/routes/admin.sports-seasons.$id.participants";

const mockParams = { id: "season-1" };

function makeRequest(data: Record<string, string | null>) {
  const formData = new FormData();
  for (const [key, value] of Object.entries(data)) {
    if (value !== null) formData.set(key, value);
  }
  return new Request("http://localhost/admin/sports-seasons/season-1/participants", {
    method: "POST",
    body: formData,
  });
}

describe("admin participants action — update-participant intent", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("updates both name and externalId when valid", async () => {
    (findParticipantByName as ReturnType<typeof vi.fn>).mockResolvedValue(null);
    (updateParticipant as ReturnType<typeof vi.fn>).mockResolvedValue({});

    const result = await action({
      request: makeRequest({
        intent: "update-participant",
        participantId: "p-1",
        newName: "US Southeast",
        newExternalId: "US",
      }),
      params: mockParams,
      context: {},
    } as Parameters<typeof action>[0]);

    expect(updateParticipant).toHaveBeenCalledWith("p-1", {
      name: "US Southeast",
      externalId: "US",
    });
    expect(result).toMatchObject({ success: true, intent: "update-participant" });
  });

  it("saves null when newExternalId is blank", async () => {
    (findParticipantByName as ReturnType<typeof vi.fn>).mockResolvedValue(null);
    (updateParticipant as ReturnType<typeof vi.fn>).mockResolvedValue({});

    await action({
      request: makeRequest({
        intent: "update-participant",
        participantId: "p-1",
        newName: "Some Team",
        newExternalId: "  ",
      }),
      params: mockParams,
      context: {},
    } as Parameters<typeof action>[0]);

    expect(updateParticipant).toHaveBeenCalledWith("p-1", {
      name: "Some Team",
      externalId: null,
    });
  });

  it("returns error when name is empty", async () => {
    const result = await action({
      request: makeRequest({
        intent: "update-participant",
        participantId: "p-1",
        newName: "   ",
        newExternalId: "US",
      }),
      params: mockParams,
      context: {},
    } as Parameters<typeof action>[0]);

    expect(updateParticipant).not.toHaveBeenCalled();
    expect(result).toMatchObject({ error: "Name is required", intent: "update-participant" });
  });

  it("returns error when name conflicts with another participant", async () => {
    (findParticipantByName as ReturnType<typeof vi.fn>).mockResolvedValue({ id: "p-2", name: "US Midwest" });

    const result = await action({
      request: makeRequest({
        intent: "update-participant",
        participantId: "p-1",
        newName: "US Midwest",
        newExternalId: "US",
      }),
      params: mockParams,
      context: {},
    } as Parameters<typeof action>[0]);

    expect(updateParticipant).not.toHaveBeenCalled();
    expect(result).toMatchObject({ error: expect.stringContaining("already exists"), intent: "update-participant" });
  });

  it("allows saving same name back to the same participant (no false conflict)", async () => {
    (findParticipantByName as ReturnType<typeof vi.fn>).mockResolvedValue({ id: "p-1", name: "US Midwest" });
    (updateParticipant as ReturnType<typeof vi.fn>).mockResolvedValue({});

    const result = await action({
      request: makeRequest({
        intent: "update-participant",
        participantId: "p-1",
        newName: "US Midwest",
        newExternalId: "US",
      }),
      params: mockParams,
      context: {},
    } as Parameters<typeof action>[0]);

    expect(updateParticipant).toHaveBeenCalled();
    expect(result).toMatchObject({ success: true });
  });
});
