import { TeamDrivingOvertakeFactsDto, TeamDrivingQualifyingFactsDto, TeamDrivingRaceFactsDto, TeamDrivingRatingEventFactory } from './TeamDrivingRatingEventFactory';

describe('TeamDrivingRatingEventFactory', () => {
  describe('createFromRaceFinish', () => {
    it('should create events from race finish data', () => {
      const events = TeamDrivingRatingEventFactory.createFromRaceFinish({
        teamId: 'team-123',
        position: 1,
        incidents: 0,
        status: 'finished',
        fieldSize: 10,
        strengthOfField: 55,
        raceId: 'race-456',
      });

      expect(events.length).toBeGreaterThan(0);
      expect(events[0].teamId).toBe('team-123');
      expect(events[0].dimension.value).toBe('driving');
    });

    it('should create events for DNS status', () => {
      const events = TeamDrivingRatingEventFactory.createFromRaceFinish({
        teamId: 'team-123',
        position: 1,
        incidents: 0,
        status: 'dns',
        fieldSize: 10,
        strengthOfField: 55,
        raceId: 'race-456',
      });

      expect(events.length).toBeGreaterThan(0);
      const dnsEvent = events.find(e => e.reason.code === 'RACE_DNS');
      expect(dnsEvent).toBeDefined();
      expect(dnsEvent?.delta.value).toBeLessThan(0);
    });

    it('should create events for DNF status', () => {
      const events = TeamDrivingRatingEventFactory.createFromRaceFinish({
        teamId: 'team-123',
        position: 5,
        incidents: 2,
        status: 'dnf',
        fieldSize: 10,
        strengthOfField: 55,
        raceId: 'race-456',
      });

      expect(events.length).toBeGreaterThan(0);
      const dnfEvent = events.find(e => e.reason.code === 'RACE_DNF');
      expect(dnfEvent).toBeDefined();
      expect(dnfEvent?.delta.value).toBe(-15);
    });

    it('should create events for DSQ status', () => {
      const events = TeamDrivingRatingEventFactory.createFromRaceFinish({
        teamId: 'team-123',
        position: 5,
        incidents: 0,
        status: 'dsq',
        fieldSize: 10,
        strengthOfField: 55,
        raceId: 'race-456',
      });

      expect(events.length).toBeGreaterThan(0);
      const dsqEvent = events.find(e => e.reason.code === 'RACE_DSQ');
      expect(dsqEvent).toBeDefined();
      expect(dsqEvent?.delta.value).toBe(-25);
    });

    it('should create events for AFK status', () => {
      const events = TeamDrivingRatingEventFactory.createFromRaceFinish({
        teamId: 'team-123',
        position: 5,
        incidents: 0,
        status: 'afk',
        fieldSize: 10,
        strengthOfField: 55,
        raceId: 'race-456',
      });

      expect(events.length).toBeGreaterThan(0);
      const afkEvent = events.find(e => e.reason.code === 'RACE_AFK');
      expect(afkEvent).toBeDefined();
      expect(afkEvent?.delta.value).toBe(-20);
    });

    it('should apply incident penalties', () => {
      const events = TeamDrivingRatingEventFactory.createFromRaceFinish({
        teamId: 'team-123',
        position: 3,
        incidents: 5,
        status: 'finished',
        fieldSize: 10,
        strengthOfField: 55,
        raceId: 'race-456',
      });

      const incidentEvent = events.find(e => e.reason.code === 'RACE_INCIDENTS');
      expect(incidentEvent).toBeDefined();
      expect(incidentEvent?.delta.value).toBeLessThan(0);
    });

    it('should apply gain bonus for beating higher-rated teams', () => {
      const events = TeamDrivingRatingEventFactory.createFromRaceFinish({
        teamId: 'team-123',
        position: 1,
        incidents: 0,
        status: 'finished',
        fieldSize: 10,
        strengthOfField: 65, // High strength
        raceId: 'race-456',
      });

      const gainEvent = events.find(e => e.reason.code === 'RACE_GAIN_BONUS');
      expect(gainEvent).toBeDefined();
      expect(gainEvent?.delta.value).toBeGreaterThan(0);
      expect(gainEvent?.weight).toBe(0.5);
    });

    it('should create pace events when pace is provided', () => {
      const events = TeamDrivingRatingEventFactory.createFromRaceFinish({
        teamId: 'team-123',
        position: 3,
        incidents: 0,
        status: 'finished',
        fieldSize: 10,
        strengthOfField: 55,
        raceId: 'race-456',
        pace: 80,
      });

      const paceEvent = events.find(e => e.reason.code === 'RACE_PACE');
      expect(paceEvent).toBeDefined();
      expect(paceEvent?.delta.value).toBeGreaterThan(0);
      expect(paceEvent?.weight).toBe(0.3);
    });

    it('should create consistency events when consistency is provided', () => {
      const events = TeamDrivingRatingEventFactory.createFromRaceFinish({
        teamId: 'team-123',
        position: 3,
        incidents: 0,
        status: 'finished',
        fieldSize: 10,
        strengthOfField: 55,
        raceId: 'race-456',
        consistency: 85,
      });

      const consistencyEvent = events.find(e => e.reason.code === 'RACE_CONSISTENCY');
      expect(consistencyEvent).toBeDefined();
      expect(consistencyEvent?.delta.value).toBeGreaterThan(0);
      expect(consistencyEvent?.weight).toBe(0.3);
    });

    it('should create teamwork events when teamwork is provided', () => {
      const events = TeamDrivingRatingEventFactory.createFromRaceFinish({
        teamId: 'team-123',
        position: 3,
        incidents: 0,
        status: 'finished',
        fieldSize: 10,
        strengthOfField: 55,
        raceId: 'race-456',
        teamwork: 90,
      });

      const teamworkEvent = events.find(e => e.reason.code === 'RACE_TEAMWORK');
      expect(teamworkEvent).toBeDefined();
      expect(teamworkEvent?.delta.value).toBeGreaterThan(0);
      expect(teamworkEvent?.weight).toBe(0.4);
    });

    it('should create sportsmanship events when sportsmanship is provided', () => {
      const events = TeamDrivingRatingEventFactory.createFromRaceFinish({
        teamId: 'team-123',
        position: 3,
        incidents: 0,
        status: 'finished',
        fieldSize: 10,
        strengthOfField: 55,
        raceId: 'race-456',
        sportsmanship: 95,
      });

      const sportsmanshipEvent = events.find(e => e.reason.code === 'RACE_SPORTSMANSHIP');
      expect(sportsmanshipEvent).toBeDefined();
      expect(sportsmanshipEvent?.delta.value).toBeGreaterThan(0);
      expect(sportsmanshipEvent?.weight).toBe(0.3);
    });
  });

  describe('createDrivingEventsFromRace', () => {
    it('should create events for multiple teams', () => {
      const raceFacts: TeamDrivingRaceFactsDto = {
        raceId: 'race-456',
        teamId: 'team-123',
        results: [
          {
            teamId: 'team-123',
            position: 1,
            incidents: 0,
            status: 'finished',
            fieldSize: 3,
            strengthOfField: 55,
          },
          {
            teamId: 'team-456',
            position: 2,
            incidents: 1,
            status: 'finished',
            fieldSize: 3,
            strengthOfField: 55,
          },
        ],
      };

      const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromRace(raceFacts);

      expect(eventsByTeam.size).toBe(2);
      expect(eventsByTeam.get('team-123')).toBeDefined();
      expect(eventsByTeam.get('team-456')).toBeDefined();
    });

    it('should handle empty results', () => {
      const raceFacts: TeamDrivingRaceFactsDto = {
        raceId: 'race-456',
        teamId: 'team-123',
        results: [],
      };

      const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromRace(raceFacts);

      expect(eventsByTeam.size).toBe(0);
    });

    it('should skip teams with no events', () => {
      const raceFacts: TeamDrivingRaceFactsDto = {
        raceId: 'race-456',
        teamId: 'team-123',
        results: [
          {
            teamId: 'team-123',
            position: 1,
            incidents: 0,
            status: 'finished',
            fieldSize: 1,
            strengthOfField: 55,
          },
        ],
      };

      const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromRace(raceFacts);

      expect(eventsByTeam.size).toBe(1);
      expect(eventsByTeam.get('team-123')?.length).toBeGreaterThan(0);
    });

    it('should handle optional ratings in results', () => {
      const raceFacts: TeamDrivingRaceFactsDto = {
        raceId: 'race-456',
        teamId: 'team-123',
        results: [
          {
            teamId: 'team-123',
            position: 1,
            incidents: 0,
            status: 'finished',
            fieldSize: 3,
            strengthOfField: 65,
            pace: 85,
            consistency: 80,
            teamwork: 90,
            sportsmanship: 95,
          },
        ],
      };

      const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromRace(raceFacts);
      const events = eventsByTeam.get('team-123')!;

      expect(events.length).toBeGreaterThan(5);
      expect(events.find(e => e.reason.code === 'RACE_PACE')).toBeDefined();
      expect(events.find(e => e.reason.code === 'RACE_CONSISTENCY')).toBeDefined();
      expect(events.find(e => e.reason.code === 'RACE_TEAMWORK')).toBeDefined();
      expect(events.find(e => e.reason.code === 'RACE_SPORTSMANSHIP')).toBeDefined();
    });
  });

  describe('createFromQualifying', () => {
    it('should create qualifying events', () => {
      const events = TeamDrivingRatingEventFactory.createFromQualifying({
        teamId: 'team-123',
        qualifyingPosition: 3,
        fieldSize: 10,
        raceId: 'race-456',
      });

      expect(events.length).toBeGreaterThan(0);
      expect(events[0].teamId).toBe('team-123');
      expect(events[0].dimension.value).toBe('driving');
      expect(events[0].reason.code).toBe('RACE_QUALIFYING');
      expect(events[0].weight).toBe(0.25);
    });
  });

  describe('createDrivingEventsFromQualifying', () => {
    it('should create events for multiple teams', () => {
      const qualifyingFacts: TeamDrivingQualifyingFactsDto = {
        raceId: 'race-456',
        results: [
          {
            teamId: 'team-123',
            qualifyingPosition: 1,
            fieldSize: 10,
          },
          {
            teamId: 'team-456',
            qualifyingPosition: 5,
            fieldSize: 10,
          },
        ],
      };

      const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromQualifying(qualifyingFacts);

      expect(eventsByTeam.size).toBe(2);
      expect(eventsByTeam.get('team-123')).toBeDefined();
      expect(eventsByTeam.get('team-456')).toBeDefined();
    });
  });

  describe('createFromOvertakeStats', () => {
    it('should create overtake events', () => {
      const events = TeamDrivingRatingEventFactory.createFromOvertakeStats({
        teamId: 'team-123',
        overtakes: 5,
        successfulDefenses: 3,
        raceId: 'race-456',
      });

      expect(events.length).toBeGreaterThan(0);
      const overtakeEvent = events.find(e => e.reason.code === 'RACE_OVERTAKE');
      expect(overtakeEvent).toBeDefined();
      expect(overtakeEvent?.delta.value).toBeGreaterThan(0);
    });

    it('should create defense events', () => {
      const events = TeamDrivingRatingEventFactory.createFromOvertakeStats({
        teamId: 'team-123',
        overtakes: 0,
        successfulDefenses: 4,
        raceId: 'race-456',
      });

      const defenseEvent = events.find(e => e.reason.code === 'RACE_DEFENSE');
      expect(defenseEvent).toBeDefined();
      expect(defenseEvent?.delta.value).toBeGreaterThan(0);
    });
  });

  describe('createDrivingEventsFromOvertakes', () => {
    it('should create events for multiple teams', () => {
      const overtakeFacts: TeamDrivingOvertakeFactsDto = {
        raceId: 'race-456',
        results: [
          {
            teamId: 'team-123',
            overtakes: 3,
            successfulDefenses: 2,
          },
          {
            teamId: 'team-456',
            overtakes: 1,
            successfulDefenses: 5,
          },
        ],
      };

      const eventsByTeam = TeamDrivingRatingEventFactory.createDrivingEventsFromOvertakes(overtakeFacts);

      expect(eventsByTeam.size).toBe(2);
      expect(eventsByTeam.get('team-123')).toBeDefined();
      expect(eventsByTeam.get('team-456')).toBeDefined();
    });
  });

  describe('createFromPenalty', () => {
    it('should create driving penalty event', () => {
      const events = TeamDrivingRatingEventFactory.createFromPenalty({
        teamId: 'team-123',
        penaltyType: 'minor',
        severity: 'low',
      });

      const drivingEvent = events.find(e => e.dimension.value === 'driving');
      expect(drivingEvent).toBeDefined();
      expect(drivingEvent?.delta.value).toBeLessThan(0);
    });

    it('should create admin trust penalty event', () => {
      const events = TeamDrivingRatingEventFactory.createFromPenalty({
        teamId: 'team-123',
        penaltyType: 'minor',
        severity: 'low',
      });

      const adminEvent = events.find(e => e.dimension.value === 'adminTrust');
      expect(adminEvent).toBeDefined();
      expect(adminEvent?.delta.value).toBeLessThan(0);
    });

    it('should apply severity multipliers', () => {
      const lowEvents = TeamDrivingRatingEventFactory.createFromPenalty({
        teamId: 'team-123',
        penaltyType: 'major',
        severity: 'low',
      });

      const highEvents = TeamDrivingRatingEventFactory.createFromPenalty({
        teamId: 'team-123',
        penaltyType: 'major',
        severity: 'high',
      });

      const lowDelta = lowEvents.find(e => e.dimension.value === 'driving')?.delta.value || 0;
      const highDelta = highEvents.find(e => e.dimension.value === 'driving')?.delta.value || 0;

      expect(highDelta).toBeLessThan(lowDelta);
    });
  });

  describe('createFromVote', () => {
    it('should create positive vote event', () => {
      const events = TeamDrivingRatingEventFactory.createFromVote({
        teamId: 'team-123',
        outcome: 'positive',
        voteCount: 10,
        eligibleVoterCount: 15,
        percentPositive: 80,
      });

      expect(events.length).toBeGreaterThan(0);
      expect(events[0].dimension.value).toBe('adminTrust');
      expect(events[0].delta.value).toBeGreaterThan(0);
    });

    it('should create negative vote event', () => {
      const events = TeamDrivingRatingEventFactory.createFromVote({
        teamId: 'team-123',
        outcome: 'negative',
        voteCount: 10,
        eligibleVoterCount: 15,
        percentPositive: 20,
      });

      expect(events.length).toBeGreaterThan(0);
      expect(events[0].dimension.value).toBe('adminTrust');
      expect(events[0].delta.value).toBeLessThan(0);
    });

    it('should weight by vote count', () => {
      const events = TeamDrivingRatingEventFactory.createFromVote({
        teamId: 'team-123',
        outcome: 'positive',
        voteCount: 20,
        eligibleVoterCount: 20,
        percentPositive: 100,
      });

      expect(events[0].weight).toBe(20);
    });
  });

  describe('createFromAdminAction', () => {
    it('should create admin action bonus event', () => {
      const events = TeamDrivingRatingEventFactory.createFromAdminAction({
        teamId: 'team-123',
        actionType: 'bonus',
      });

      expect(events.length).toBeGreaterThan(0);
      expect(events[0].dimension.value).toBe('adminTrust');
      expect(events[0].delta.value).toBeGreaterThan(0);
    });

    it('should create admin action penalty event', () => {
      const events = TeamDrivingRatingEventFactory.createFromAdminAction({
        teamId: 'team-123',
        actionType: 'penalty',
        severity: 'high',
      });

      expect(events.length).toBeGreaterThan(0);
      expect(events[0].dimension.value).toBe('adminTrust');
      expect(events[0].delta.value).toBeLessThan(0);
    });

    it('should create admin warning response event', () => {
      const events = TeamDrivingRatingEventFactory.createFromAdminAction({
        teamId: 'team-123',
        actionType: 'warning',
      });

      expect(events.length).toBeGreaterThan(0);
      expect(events[0].dimension.value).toBe('adminTrust');
      expect(events[0].delta.value).toBeGreaterThan(0);
    });
  });
});