import { describe, it, expect } from "vitest";
import { calculateFantasyPoints, 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("Qualifying Points - Fantasy Scoring Integration", () => {
  describe("QP to Fantasy Points Conversion", () => {
    it("should convert 1st place in QP standings to 100 fantasy points", () => {
      const points = calculateFantasyPoints(1, DEFAULT_SCORING);
      expect(points).toBe(100);
    });

    it("should convert 2nd place in QP standings to 70 fantasy points", () => {
      const points = calculateFantasyPoints(2, DEFAULT_SCORING);
      expect(points).toBe(70);
    });

    it("should convert 8th place in QP standings to 15 fantasy points", () => {
      const points = calculateFantasyPoints(8, DEFAULT_SCORING);
      expect(points).toBe(15);
    });

    it("should convert 9th+ place in QP standings to 0 fantasy points", () => {
      const points9th = calculateFantasyPoints(9, DEFAULT_SCORING);
      const points10th = calculateFantasyPoints(10, DEFAULT_SCORING);

      expect(points9th).toBe(0);
      expect(points10th).toBe(0);
    });
  });

  describe("Full Season Workflow Simulation", () => {
    it("should calculate correct final fantasy points after 4 majors", () => {
      // Simulate 4 major tournaments with 3 participants
      // Each major awards QP based on placement

      type Participant = {
        name: string;
        totalQP: number;
        majorResults: number[];
      };

      const participants: Participant[] = [
        { name: "Tiger Woods", totalQP: 0, majorResults: [1, 2, 2, 1] }, // Wins 2, 2nd in 2
        { name: "Rory McIlroy", totalQP: 0, majorResults: [2, 1, 3, 2] }, // Wins 1, 2nd in 2, 3rd in 1
        { name: "Scottie Scheffler", totalQP: 0, majorResults: [3, 3, 1, 3] }, // Wins 1, 3rd in 3
      ];

      // QP awards based on placement
      const qpMap: Record<number, number> = {
        1: 20,
        2: 14,
        3: 10,
        4: 8,
        5: 5,
        6: 5,
        7: 3,
        8: 3,
      };

      // Calculate total QP for each participant
      for (const participant of participants) {
        for (const placement of participant.majorResults) {
          participant.totalQP += qpMap[placement] || 0;
        }
      }

      // Sort by total QP (highest first)
      participants.sort((a, b) => b.totalQP - a.totalQP);

      // Verify QP totals
      expect(participants[0].name).toBe("Tiger Woods");
      expect(participants[0].totalQP).toBe(68); // 20+14+14+20

      expect(participants[1].name).toBe("Rory McIlroy");
      expect(participants[1].totalQP).toBe(58); // 14+20+10+14

      expect(participants[2].name).toBe("Scottie Scheffler");
      expect(participants[2].totalQP).toBe(50); // 10+10+20+10

      // Assign fantasy placements based on QP rankings
      const fantasyPlacements = [1, 2, 3]; // Top 3 get 1st, 2nd, 3rd

      // Calculate fantasy points
      const fantasyPoints = fantasyPlacements.map(placement =>
        calculateFantasyPoints(placement, DEFAULT_SCORING)
      );

      expect(fantasyPoints[0]).toBe(100); // Tiger's fantasy points
      expect(fantasyPoints[1]).toBe(70); // Rory's fantasy points
      expect(fantasyPoints[2]).toBe(50); // Scottie's fantasy points
    });

    it("should handle ties in QP standings (Q5)", () => {
      // Two participants tie with same QP total
      type ParticipantWithQP = {
        name: string;
        totalQP: number;
        finalPlacement: number;
      };

      const participants: ParticipantWithQP[] = [
        { name: "Player A", totalQP: 50, finalPlacement: 1 },
        { name: "Player B", totalQP: 30, finalPlacement: 2 }, // Tied for 2nd
        { name: "Player C", totalQP: 30, finalPlacement: 2 }, // Tied for 2nd
        { name: "Player D", totalQP: 20, finalPlacement: 4 }, // Ranked 4th (skips 3)
      ];

      // Both tied participants get placement 2
      const tied = participants.filter(p => p.totalQP === 30);
      expect(tied).toHaveLength(2);
      expect(tied[0].finalPlacement).toBe(2);
      expect(tied[1].finalPlacement).toBe(2);

      // Both would earn 2nd place fantasy points
      const points = calculateFantasyPoints(2, DEFAULT_SCORING);
      expect(points).toBe(70);
    });

    it("should handle participants beyond top 8 getting 0 points", () => {
      // 10 participants, but only top 8 score
      const participants = Array.from({ length: 10 }, (_, i) => ({
        name: `Player ${i + 1}`,
        qp: 100 - i * 10, // Descending QP
        finalPlacement: i + 1,
      }));

      // Top 8 get points, 9th and 10th get 0
      const participant9 = participants[8];
      const participant10 = participants[9];

      const points9 = calculateFantasyPoints(participant9.finalPlacement, DEFAULT_SCORING);
      const points10 = calculateFantasyPoints(participant10.finalPlacement, DEFAULT_SCORING);

      expect(points9).toBe(0);
      expect(points10).toBe(0);
    });
  });

  describe("Custom Scoring Rules", () => {
    it("should apply custom scoring rules to QP standings", () => {
      const customScoring: ScoringRules = {
        pointsFor1st: 200,
        pointsFor2nd: 150,
        pointsFor3rd: 100,
        pointsFor4th: 75,
        pointsFor5th: 50,
        pointsFor6th: 40,
        pointsFor7th: 30,
        pointsFor8th: 20,
      };

      const points1st = calculateFantasyPoints(1, customScoring);
      const points8th = calculateFantasyPoints(8, customScoring);

      expect(points1st).toBe(200);
      expect(points8th).toBe(20);
    });
  });

  describe("Edge Cases", () => {
    it("should handle all participants tied for 1st in QP", () => {
      // Unlikely but possible scenario
      const participants = [
        { name: "P1", qp: 40, placement: 1 },
        { name: "P2", qp: 40, placement: 1 },
        { name: "P3", qp: 40, placement: 1 },
      ];

      // All get 1st place fantasy points
      const points = participants.map(p =>
        calculateFantasyPoints(p.placement, DEFAULT_SCORING)
      );

      expect(points).toEqual([100, 100, 100]);
    });

    it("should handle participant with 0 QP (didn't score in any major)", () => {
      const participant = {
        name: "No Score Player",
        qp: 0,
        placement: 20, // Beyond scoring range
      };

      const points = calculateFantasyPoints(participant.placement, DEFAULT_SCORING);

      expect(points).toBe(0);
    });
  });
});
