import { describe, it, expect } from 'vitest';

import { DropScoreApplier } from '@core/racing/domain/services/DropScoreApplier';
import type { EventPointsEntry } from '@core/racing/domain/services/DropScoreApplier';
import type { DropScorePolicy } from '@core/racing/domain/types/DropScorePolicy';

describe('DropScoreApplier', () => {
  it('with strategy none counts all events and drops none', () => {
    const applier = new DropScoreApplier();

    const policy: DropScorePolicy = {
      strategy: 'none',
    };

    const events: EventPointsEntry[] = [
      { eventId: 'event-1', points: 25 },
      { eventId: 'event-2', points: 18 },
      { eventId: 'event-3', points: 15 },
    ];

    const result = applier.apply(policy, events);

    expect(result.counted).toHaveLength(3);
    expect(result.dropped).toHaveLength(0);
    expect(result.totalPoints).toBe(25 + 18 + 15);
  });

  it('with bestNResults keeps the highest scoring events and drops the rest', () => {
    const applier = new DropScoreApplier();

    const policy: DropScorePolicy = {
      strategy: 'bestNResults',
      count: 6,
    };

    const events: EventPointsEntry[] = [
      { eventId: 'event-1', points: 25 },
      { eventId: 'event-2', points: 18 },
      { eventId: 'event-3', points: 15 },
      { eventId: 'event-4', points: 12 },
      { eventId: 'event-5', points: 10 },
      { eventId: 'event-6', points: 8 },
      { eventId: 'event-7', points: 6 },
      { eventId: 'event-8', points: 4 },
    ];

    const result = applier.apply(policy, events);

    expect(result.counted).toHaveLength(6);
    expect(result.dropped).toHaveLength(2);

    const countedIds = result.counted.map((e) => e.eventId);
    expect(countedIds).toEqual([
      'event-1',
      'event-2',
      'event-3',
      'event-4',
      'event-5',
      'event-6',
    ]);

    const droppedIds = result.dropped.map((e) => e.eventId);
    expect(droppedIds).toEqual(['event-7', 'event-8']);

    expect(result.totalPoints).toBe(25 + 18 + 15 + 12 + 10 + 8);
  });

  it('bestNResults with count greater than available events counts all of them', () => {
    const applier = new DropScoreApplier();

    const policy: DropScorePolicy = {
      strategy: 'bestNResults',
      count: 10,
    };

    const events: EventPointsEntry[] = [
      { eventId: 'event-1', points: 25 },
      { eventId: 'event-2', points: 18 },
      { eventId: 'event-3', points: 15 },
    ];

    const result = applier.apply(policy, events);

    expect(result.counted).toHaveLength(3);
    expect(result.dropped).toHaveLength(0);
    expect(result.totalPoints).toBe(25 + 18 + 15);
  });
});