import { describe, it, expect, vi, beforeEach } from 'vitest';
import { addToQueue, getTeamQueue, isParticipantInQueue } from '~/models/draft-queue';

// Mock the models
vi.mock('~/models/draft-queue', () => ({
  addToQueue: vi.fn(),
  getTeamQueue: vi.fn(),
  isParticipantInQueue: vi.fn(),
}));

describe('Queue Add - Duplicate Prevention', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should successfully add a participant to an empty queue', async () => {
    const teamId = 'team-1';
    const participantId = 'participant-1';
    const seasonId = 'season-1';

    // Mock that participant is not in queue
    vi.mocked(isParticipantInQueue).mockResolvedValue(false);

    // Mock empty queue
    vi.mocked(getTeamQueue).mockResolvedValue([]);

    // Mock successful add
    const mockQueueItem = {
      id: 'queue-1',
      seasonId,
      teamId,
      participantId,
      queuePosition: 1,
      createdAt: new Date(),
      updatedAt: new Date(),
    };
    vi.mocked(addToQueue).mockResolvedValue(mockQueueItem);

    // Simulate the logic
    const alreadyInQueue = await isParticipantInQueue(teamId, participantId);
    expect(alreadyInQueue).toBe(false);

    const currentQueue = await getTeamQueue(teamId);
    const queuePosition = currentQueue.length + 1;

    const result = await addToQueue({
      seasonId,
      teamId,
      participantId,
      queuePosition,
    });

    expect(isParticipantInQueue).toHaveBeenCalledWith(teamId, participantId);
    expect(getTeamQueue).toHaveBeenCalledWith(teamId);
    expect(addToQueue).toHaveBeenCalledWith({
      seasonId,
      teamId,
      participantId,
      queuePosition: 1,
    });
    expect(result.participantId).toBe(participantId);
    expect(result.queuePosition).toBe(1);
  });

  it('should prevent adding duplicate participant to queue', async () => {
    const teamId = 'team-1';
    const participantId = 'participant-1';

    // Mock that participant is already in queue
    vi.mocked(isParticipantInQueue).mockResolvedValue(true);

    const alreadyInQueue = await isParticipantInQueue(teamId, participantId);

    expect(alreadyInQueue).toBe(true);
    expect(isParticipantInQueue).toHaveBeenCalledWith(teamId, participantId);

    // Should not call addToQueue if already in queue
    expect(addToQueue).not.toHaveBeenCalled();
  });

  it('should add participant to queue when other participants exist', async () => {
    const teamId = 'team-1';
    const newParticipantId = 'participant-3';
    const seasonId = 'season-1';

    // Mock existing queue with 2 participants
    const existingQueue = [
      {
        id: 'queue-1',
        seasonId,
        teamId,
        participantId: 'participant-1',
        queuePosition: 1,
        createdAt: new Date(),
        updatedAt: new Date(),
      },
      {
        id: 'queue-2',
        seasonId,
        teamId,
        participantId: 'participant-2',
        queuePosition: 2,
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    ];

    vi.mocked(isParticipantInQueue).mockResolvedValue(false);
    vi.mocked(getTeamQueue).mockResolvedValue(existingQueue);

    const mockQueueItem = {
      id: 'queue-3',
      seasonId,
      teamId,
      participantId: newParticipantId,
      queuePosition: 3,
      createdAt: new Date(),
      updatedAt: new Date(),
    };
    vi.mocked(addToQueue).mockResolvedValue(mockQueueItem);

    // Simulate the logic
    const alreadyInQueue = await isParticipantInQueue(teamId, newParticipantId);
    expect(alreadyInQueue).toBe(false);

    const currentQueue = await getTeamQueue(teamId);
    const queuePosition = currentQueue.length + 1;

    const result = await addToQueue({
      seasonId,
      teamId,
      participantId: newParticipantId,
      queuePosition,
    });

    expect(result.queuePosition).toBe(3);
    expect(result.participantId).toBe(newParticipantId);
  });

  it('should prevent adding same participant multiple times in quick succession', async () => {
    const teamId = 'team-1';
    const participantId = 'participant-1';

    // First call - not in queue
    vi.mocked(isParticipantInQueue).mockResolvedValueOnce(false);

    const firstCheck = await isParticipantInQueue(teamId, participantId);
    expect(firstCheck).toBe(false);

    // Second call (rapid click) - now in queue
    vi.mocked(isParticipantInQueue).mockResolvedValueOnce(true);

    const secondCheck = await isParticipantInQueue(teamId, participantId);
    expect(secondCheck).toBe(true);

    // Verify the function was called twice
    expect(isParticipantInQueue).toHaveBeenCalledTimes(2);
  });

  it('should allow adding different participants to the same queue', async () => {
    const teamId = 'team-1';
    const participant1 = 'participant-1';
    const participant2 = 'participant-2';
    const seasonId = 'season-1';

    // Add first participant
    vi.mocked(isParticipantInQueue).mockResolvedValueOnce(false);
    vi.mocked(getTeamQueue).mockResolvedValueOnce([]);
    vi.mocked(addToQueue).mockResolvedValueOnce({
      id: 'queue-1',
      seasonId,
      teamId,
      participantId: participant1,
      queuePosition: 1,
      createdAt: new Date(),
      updatedAt: new Date(),
    });

    let alreadyInQueue = await isParticipantInQueue(teamId, participant1);
    expect(alreadyInQueue).toBe(false);

    await addToQueue({
      seasonId,
      teamId,
      participantId: participant1,
      queuePosition: 1,
    });

    // Add second participant
    vi.mocked(isParticipantInQueue).mockResolvedValueOnce(false);
    vi.mocked(getTeamQueue).mockResolvedValueOnce([
      {
        id: 'queue-1',
        seasonId,
        teamId,
        participantId: participant1,
        queuePosition: 1,
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    ]);
    vi.mocked(addToQueue).mockResolvedValueOnce({
      id: 'queue-2',
      seasonId,
      teamId,
      participantId: participant2,
      queuePosition: 2,
      createdAt: new Date(),
      updatedAt: new Date(),
    });

    alreadyInQueue = await isParticipantInQueue(teamId, participant2);
    expect(alreadyInQueue).toBe(false);

    const result = await addToQueue({
      seasonId,
      teamId,
      participantId: participant2,
      queuePosition: 2,
    });

    expect(result.participantId).toBe(participant2);
    expect(addToQueue).toHaveBeenCalledTimes(2);
  });

  it('should handle the case where participant is in another teams queue', async () => {
    const team1Id = 'team-1';
    const team2Id = 'team-2';
    const participantId = 'participant-1';
    const seasonId = 'season-1';

    // Participant is in team1's queue
    vi.mocked(isParticipantInQueue).mockImplementation(async (teamId, pId) => {
      return teamId === team1Id && pId === participantId;
    });

    // Check team1 - should be in queue
    const inTeam1Queue = await isParticipantInQueue(team1Id, participantId);
    expect(inTeam1Queue).toBe(true);

    // Check team2 - should not be in queue
    const inTeam2Queue = await isParticipantInQueue(team2Id, participantId);
    expect(inTeam2Queue).toBe(false);

    // Should be able to add to team2
    vi.mocked(getTeamQueue).mockResolvedValue([]);
    vi.mocked(addToQueue).mockResolvedValue({
      id: 'queue-2',
      seasonId,
      teamId: team2Id,
      participantId,
      queuePosition: 1,
      createdAt: new Date(),
      updatedAt: new Date(),
    });

    const result = await addToQueue({
      seasonId,
      teamId: team2Id,
      participantId,
      queuePosition: 1,
    });

    expect(result.teamId).toBe(team2Id);
  });
});
