import { describe, it, expect } from "vitest";
import { calculateFantasyPoints, calculateAveragedPoints, type ScoringRules } from "../scoring-rules";

const DEFAULT_SCORING: ScoringRules = {
  pointsFor1st: 100,
  pointsFor2nd: 70,
  pointsFor3rd: 50,
  pointsFor4th: 40,
  pointsFor5th: 25,
  pointsFor6th: 25,
  pointsFor7th: 15,
  pointsFor8th: 15,
};

describe("Season Standings (F1 Pattern)", () => {
  describe("Basic Placement Scoring", () => {
    it("should calculate points for 1st place finisher", () => {
      const points = calculateFantasyPoints(1, DEFAULT_SCORING);
      expect(points).toBe(100);
    });

    it("should calculate points for 8th place finisher", () => {
      const points = calculateFantasyPoints(8, DEFAULT_SCORING);
      expect(points).toBe(15);
    });

    it("should return 0 points for finishers beyond 8th place", () => {
      const points = calculateFantasyPoints(0, DEFAULT_SCORING);
      expect(points).toBe(0);
    });
  });

  describe("Tie Scenarios", () => {
    it("should handle 2-way tie for 3rd place", () => {
      // Two drivers tied for 3rd get average of 3rd and 4th place points
      const points = calculateAveragedPoints([3, 4], DEFAULT_SCORING);
      // (50 + 40) / 2 = 45
      expect(points).toBe(45);
    });

    it("should handle 3-way tie for 5th place", () => {
      // Three drivers tied for 5th share 5th, 6th, and 7th place points
      const points = calculateAveragedPoints([5, 6, 7], DEFAULT_SCORING);
      // (25 + 25 + 15) / 3 = 21.67
      expect(points).toBeCloseTo(21.67, 2);
    });

    it("should handle 4-way tie for 1st place", () => {
      // Four drivers tied for 1st (unlikely but possible)
      const points = calculateAveragedPoints([1, 2, 3, 4], DEFAULT_SCORING);
      // (100 + 70 + 50 + 40) / 4 = 65
      expect(points).toBe(65);
    });
  });

  describe("Season Standings Simulation", () => {
    it("should correctly score a complete F1-style season (no ties)", () => {
      // Simulate final standings positions 1-10
      const standings = [
        { driver: "Max Verstappen", position: 1, fantasyPoints: 100 },
        { driver: "Lewis Hamilton", position: 2, fantasyPoints: 70 },
        { driver: "Charles Leclerc", position: 3, fantasyPoints: 50 },
        { driver: "Lando Norris", position: 4, fantasyPoints: 40 },
        { driver: "Carlos Sainz", position: 5, fantasyPoints: 25 },
        { driver: "George Russell", position: 6, fantasyPoints: 25 },
        { driver: "Sergio Perez", position: 7, fantasyPoints: 15 },
        { driver: "Fernando Alonso", position: 8, fantasyPoints: 15 },
        { driver: "Oscar Piastri", position: 9, fantasyPoints: 0 }, // Beyond top 8
        { driver: "Pierre Gasly", position: 10, fantasyPoints: 0 }, // Beyond top 8
      ];

      standings.forEach((entry) => {
        const points = calculateFantasyPoints(entry.position, DEFAULT_SCORING);
        expect(points).toBe(entry.fantasyPoints);
      });

      // Total points if one team drafted all top 8
      const totalTop8 = 100 + 70 + 50 + 40 + 25 + 25 + 15 + 15;
      expect(totalTop8).toBe(340);
    });

    it("should correctly score season with tied positions", () => {
      // Simulate standings where 3rd, 4th, and 5th are tied
      const _standings = [
        { position: 1, expected: 100 },
        { position: 2, expected: 70 },
        // Three tied for 3rd place - each gets placement 3
        // When scoring, these will share 3rd, 4th, 5th
        { position: 3, base: 50 }, // Will be averaged: (50+40+25)/3
        { position: 3, base: 50 },
        { position: 3, base: 50 },
        { position: 6, expected: 25 },
        { position: 7, expected: 15 },
        { position: 8, expected: 15 },
      ];

      // Verify first two positions
      expect(calculateFantasyPoints(1, DEFAULT_SCORING)).toBe(100);
      expect(calculateFantasyPoints(2, DEFAULT_SCORING)).toBe(70);

      // Verify tied positions get averaged
      const tiedPoints = calculateAveragedPoints([3, 4, 5], DEFAULT_SCORING);
      expect(tiedPoints).toBeCloseTo(38.33, 2); // (50 + 40 + 25) / 3

      // Verify remaining positions
      expect(calculateFantasyPoints(6, DEFAULT_SCORING)).toBe(25);
      expect(calculateFantasyPoints(7, DEFAULT_SCORING)).toBe(15);
      expect(calculateFantasyPoints(8, DEFAULT_SCORING)).toBe(15);
    });

    it("should handle ties that cross the 8th place boundary", () => {
      // Simulate where 7th, 8th, and 9th are tied
      // In practice, 7th and 8th would score, 9th would get 0

      // First 7 and 8 get points
      expect(calculateFantasyPoints(7, DEFAULT_SCORING)).toBe(15);
      expect(calculateFantasyPoints(8, DEFAULT_SCORING)).toBe(15);

      // If they share 7th and 8th place
      const shared7and8 = calculateAveragedPoints([7, 8], DEFAULT_SCORING);
      expect(shared7and8).toBe(15); // (15 + 15) / 2 = 15

      // 9th gets 0
      expect(calculateFantasyPoints(0, DEFAULT_SCORING)).toBe(0);
    });
  });

  describe("Custom Scoring Rules", () => {
    it("should work with custom F1 league scoring rules", () => {
      const customScoring: ScoringRules = {
        pointsFor1st: 150,
        pointsFor2nd: 100,
        pointsFor3rd: 75,
        pointsFor4th: 60,
        pointsFor5th: 50,
        pointsFor6th: 40,
        pointsFor7th: 30,
        pointsFor8th: 20,
      };

      expect(calculateFantasyPoints(1, customScoring)).toBe(150);
      expect(calculateFantasyPoints(8, customScoring)).toBe(20);

      // Tied positions
      const tied3rd = calculateAveragedPoints([3, 4], customScoring);
      expect(tied3rd).toBe(67.5); // (75 + 60) / 2
    });
  });

  describe("Edge Cases", () => {
    it("should handle all 8 positions tied", () => {
      // Extremely unlikely but mathematically possible
      const allTied = calculateAveragedPoints([1, 2, 3, 4, 5, 6, 7, 8], DEFAULT_SCORING);
      // (100 + 70 + 50 + 40 + 25 + 25 + 15 + 15) / 8 = 42.5
      expect(allTied).toBe(42.5);
    });

    it("should handle only top 4 finishing (others DNF/DQ)", () => {
      // If only 4 participants finish the season
      expect(calculateFantasyPoints(1, DEFAULT_SCORING)).toBe(100);
      expect(calculateFantasyPoints(2, DEFAULT_SCORING)).toBe(70);
      expect(calculateFantasyPoints(3, DEFAULT_SCORING)).toBe(50);
      expect(calculateFantasyPoints(4, DEFAULT_SCORING)).toBe(40);

      // Positions 5-8 would have no participants
      // Any non-finishers get 0
      expect(calculateFantasyPoints(0, DEFAULT_SCORING)).toBe(0);
    });

    it("should handle single participant season", () => {
      // Only 1 participant completes the season
      const points = calculateFantasyPoints(1, DEFAULT_SCORING);
      expect(points).toBe(100);
    });
  });
});
