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("Scoring Calculator", () => {
  describe("calculateFantasyPoints", () => {
    it("should calculate points for 1st place", () => {
      const points = calculateFantasyPoints(1, DEFAULT_SCORING);
      expect(points).toBe(100);
    });

    it("should calculate points for 2nd place", () => {
      const points = calculateFantasyPoints(2, DEFAULT_SCORING);
      expect(points).toBe(70);
    });

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

    it("should return 0 for placements outside 1-8", () => {
      const points = calculateFantasyPoints(9, DEFAULT_SCORING);
      expect(points).toBe(0);
    });

    it("should handle custom scoring rules", () => {
      const customScoring: ScoringRules = {
        pointsFor1st: 200,
        pointsFor2nd: 150,
        pointsFor3rd: 100,
        pointsFor4th: 75,
        pointsFor5th: 50,
        pointsFor6th: 40,
        pointsFor7th: 30,
        pointsFor8th: 20,
      };

      const points = calculateFantasyPoints(1, customScoring);
      expect(points).toBe(200);
    });
  });

  describe("calculateAveragedPoints", () => {
    it("should average points for two-way tie (SF losers sharing 3rd/4th)", () => {
      const points = calculateAveragedPoints([3, 4], DEFAULT_SCORING);
      // (50 + 40) / 2 = 45
      expect(points).toBe(45);
    });

    it("should average points for four-way tie (QF losers sharing 5th-8th)", () => {
      const points = calculateAveragedPoints([5, 6, 7, 8], DEFAULT_SCORING);
      // (25 + 25 + 15 + 15) / 4 = 20
      expect(points).toBe(20);
    });

    it("should average points for three-way tie", () => {
      const points = calculateAveragedPoints([1, 2, 3], DEFAULT_SCORING);
      // (100 + 70 + 50) / 3 = 73.33...
      expect(points).toBeCloseTo(73.33, 2);
    });

    it("should handle single placement (no tie)", () => {
      const points = calculateAveragedPoints([1], DEFAULT_SCORING);
      expect(points).toBe(100);
    });

    it("should return 0 for empty array", () => {
      const points = calculateAveragedPoints([], DEFAULT_SCORING);
      expect(points).toBe(0);
    });

    it("should work with custom scoring rules", () => {
      const customScoring: ScoringRules = {
        pointsFor1st: 80,
        pointsFor2nd: 60,
        pointsFor3rd: 40,
        pointsFor4th: 30,
        pointsFor5th: 20,
        pointsFor6th: 20,
        pointsFor7th: 10,
        pointsFor8th: 10,
      };

      const points = calculateAveragedPoints([5, 6, 7, 8], customScoring);
      // (20 + 20 + 10 + 10) / 4 = 15
      expect(points).toBe(15);
    });
  });

  describe("Playoff Placement Scenarios", () => {
    it("should handle 8-team single elimination bracket", () => {
      // Champion: 1st (100 pts)
      const champion = calculateFantasyPoints(1, DEFAULT_SCORING);
      expect(champion).toBe(100);

      // Runner-up: 2nd (70 pts)
      const runnerUp = calculateFantasyPoints(2, DEFAULT_SCORING);
      expect(runnerUp).toBe(70);

      // SF losers: share 3rd/4th (45 pts each)
      const sfLosers = calculateAveragedPoints([3, 4], DEFAULT_SCORING);
      expect(sfLosers).toBe(45);

      // QF losers: share 5th-8th (20 pts each)
      const qfLosers = calculateAveragedPoints([5, 6, 7, 8], DEFAULT_SCORING);
      expect(qfLosers).toBe(20);
    });

    it("should handle 4-team bracket (no quarterfinals)", () => {
      // Champion: 1st (100 pts)
      const champion = calculateFantasyPoints(1, DEFAULT_SCORING);
      expect(champion).toBe(100);

      // Runner-up: 2nd (70 pts)
      const runnerUp = calculateFantasyPoints(2, DEFAULT_SCORING);
      expect(runnerUp).toBe(70);

      // SF losers: share 3rd/4th (45 pts each)
      const sfLosers = calculateAveragedPoints([3, 4], DEFAULT_SCORING);
      expect(sfLosers).toBe(45);
    });
  });

  describe("Edge Cases", () => {
    it("should handle all participants tying for 1st-8th", () => {
      const points = calculateAveragedPoints([1, 2, 3, 4, 5, 6, 7, 8], DEFAULT_SCORING);
      // (100 + 70 + 50 + 40 + 25 + 25 + 15 + 15) / 8 = 42.5
      expect(points).toBe(42.5);
    });

    it("should handle placements with same point values", () => {
      // With default scoring, 5th and 6th both get 25 points
      const points56 = calculateAveragedPoints([5, 6], DEFAULT_SCORING);
      expect(points56).toBe(25);

      // 7th and 8th both get 15 points
      const points78 = calculateAveragedPoints([7, 8], DEFAULT_SCORING);
      expect(points78).toBe(15);
    });

    it("should handle zero points for eliminated participants", () => {
      // According to Q20, participants eliminated before Elite Eight get 0 points
      const points = calculateFantasyPoints(9, DEFAULT_SCORING);
      expect(points).toBe(0);

      const points10 = calculateFantasyPoints(16, DEFAULT_SCORING);
      expect(points10).toBe(0);
    });
  });

  describe("Real-world Scenarios", () => {
    it("should correctly calculate NFL playoff points", () => {
      // NFL has 8 teams in playoffs (QF, SF, Finals)
      // Super Bowl winner: 100 pts
      const winner = calculateFantasyPoints(1, DEFAULT_SCORING);
      expect(winner).toBe(100);

      // Super Bowl loser: 70 pts
      const loser = calculateFantasyPoints(2, DEFAULT_SCORING);
      expect(loser).toBe(70);

      // Conference championship losers: 45 pts each
      const confLosers = calculateAveragedPoints([3, 4], DEFAULT_SCORING);
      expect(confLosers).toBe(45);

      // Divisional round losers: 20 pts each
      const divLosers = calculateAveragedPoints([5, 6, 7, 8], DEFAULT_SCORING);
      expect(divLosers).toBe(20);
    });

    it("should correctly calculate NCAA March Madness Elite Eight points", () => {
      // Even though 68 teams start, only Elite Eight (8 teams) get points
      // Teams eliminated before Elite Eight get 0 points

      // Champion: 100 pts
      const champion = calculateFantasyPoints(1, DEFAULT_SCORING);
      expect(champion).toBe(100);

      // Runner-up: 70 pts
      const runnerUp = calculateFantasyPoints(2, DEFAULT_SCORING);
      expect(runnerUp).toBe(70);

      // Final Four losers: 45 pts each
      const ffLosers = calculateAveragedPoints([3, 4], DEFAULT_SCORING);
      expect(ffLosers).toBe(45);

      // Elite Eight losers: 20 pts each
      const e8Losers = calculateAveragedPoints([5, 6, 7, 8], DEFAULT_SCORING);
      expect(e8Losers).toBe(20);

      // Sweet Sixteen loser (example): 0 pts
      const sweetSixteenLoser = calculateFantasyPoints(9, DEFAULT_SCORING);
      expect(sweetSixteenLoser).toBe(0);
    });
  });
});
