import { describe, it, expect, vi, beforeEach } from "vitest";

// ── DB mock ────────────────────────────────────────────────────────────────

const DEFAULT_SEASON = {
  id: "season-1",
  pointsFor1st: 100, pointsFor2nd: 75, pointsFor3rd: 50,
  pointsFor4th: 40, pointsFor5th: 30, pointsFor6th: 20,
  pointsFor7th: 10, pointsFor8th: 5,
};

type PickRow = {
  participant: {
    id: string;
    name: string;
    sportsSeasonId: string;
    sportsSeason: { id: string; scoringPattern: string };
    results: { finalPosition: number | null }[];
  };
};

interface MakeDbOpts {
  season?: typeof DEFAULT_SEASON | null;
  picks?: PickRow[];
  scoringEvents?: { sportsSeasonId: string; bracketTemplateId: string | null }[];
  qualifyingTotals?: { participantId: string; totalQualifyingPoints: string }[];
  seasonParticipantResults?: { sportsSeasonId: string; finalPosition: number | null }[];
}

function makeDb(opts: MakeDbOpts = {}) {
  const {
    season = DEFAULT_SEASON,
    picks = [],
    scoringEvents = [],
    qualifyingTotals = [],
    seasonParticipantResults = [],
  } = opts;

  return {
    query: {
      seasons: {
        findFirst: vi.fn().mockResolvedValue(season),
      },
      draftPicks: {
        findMany: vi.fn().mockResolvedValue(picks),
      },
      scoringEvents: {
        findMany: vi.fn().mockResolvedValue(scoringEvents),
      },
      seasonParticipantQualifyingTotals: {
        findMany: vi.fn().mockResolvedValue(qualifyingTotals),
      },
      seasonParticipantResults: {
        findMany: vi.fn().mockResolvedValue(seasonParticipantResults),
      },
    },
  } as any;
}

import { getDraftedParticipantsWithPoints } from "../draft-pick";

function makePick(overrides: {
  id?: string;
  name?: string;
  sportsSeasonId?: string;
  scoringPattern?: string;
  finalPosition?: number | null;
}): PickRow {
  const {
    id = "p-1",
    name = "Participant One",
    sportsSeasonId = "ss-1",
    scoringPattern = "playoff_bracket",
    finalPosition = null,
  } = overrides;
  return {
    participant: {
      id,
      name,
      sportsSeasonId,
      sportsSeason: { id: sportsSeasonId, scoringPattern },
      results: finalPosition !== null ? [{ finalPosition }] : [],
    },
  };
}

describe("getDraftedParticipantsWithPoints", () => {
  beforeEach(() => vi.clearAllMocks());

  it("returns empty map when season not found", async () => {
    const db = makeDb({ season: null });
    const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);
    expect(result.size).toBe(0);
  });

  it("returns empty map when no picks", async () => {
    const db = makeDb({ picks: [] });
    const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);
    expect(result.size).toBe(0);
  });

  describe("playoff_bracket pattern", () => {
    it("returns earnedPoints based on finalPosition and scoring rules", async () => {
      const db = makeDb({
        picks: [makePick({ scoringPattern: "playoff_bracket", finalPosition: 1 })],
        scoringEvents: [{ sportsSeasonId: "ss-1", bracketTemplateId: null }],
      });

      const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);

      const ssEntry = result.get("ss-1");
      expect(ssEntry).toBeDefined();
      expect(ssEntry?.[0]).toMatchObject({
        id: "p-1",
        name: "Participant One",
        earnedPoints: 100, // pointsFor1st
        currentQP: null,
      });
    });

    it("returns null earnedPoints when no finalPosition yet", async () => {
      const db = makeDb({
        picks: [makePick({ scoringPattern: "playoff_bracket", finalPosition: null })],
        scoringEvents: [{ sportsSeasonId: "ss-1", bracketTemplateId: null }],
      });

      const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);

      expect(result.get("ss-1")?.[0]).toMatchObject({ earnedPoints: null, currentQP: null });
    });

    it("groups multiple picks by sportsSeasonId", async () => {
      const db = makeDb({
        picks: [
          makePick({ id: "p-1", name: "Alice", sportsSeasonId: "ss-1", scoringPattern: "playoff_bracket", finalPosition: 1 }),
          makePick({ id: "p-2", name: "Bob", sportsSeasonId: "ss-1", scoringPattern: "playoff_bracket", finalPosition: 2 }),
          makePick({ id: "p-3", name: "Carol", sportsSeasonId: "ss-2", scoringPattern: "playoff_bracket", finalPosition: 1 }),
        ],
        scoringEvents: [
          { sportsSeasonId: "ss-1", bracketTemplateId: null },
          { sportsSeasonId: "ss-2", bracketTemplateId: null },
        ],
      });

      const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);

      expect(result.get("ss-1")).toHaveLength(2);
      expect(result.get("ss-2")).toHaveLength(1);
    });
  });

  describe("qualifying_points pattern — active (no finalPosition)", () => {
    it("returns currentQP from participantQualifyingTotals", async () => {
      const db = makeDb({
        picks: [makePick({ id: "p-1", sportsSeasonId: "ss-1", scoringPattern: "qualifying_points", finalPosition: null })],
        qualifyingTotals: [{ participantId: "p-1", totalQualifyingPoints: "42.5" }],
      });

      const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);

      expect(result.get("ss-1")?.[0]).toMatchObject({
        earnedPoints: null,
        currentQP: 42.5,
      });
    });

    it("returns null currentQP when participant has no QP total row", async () => {
      const db = makeDb({
        picks: [makePick({ id: "p-1", sportsSeasonId: "ss-1", scoringPattern: "qualifying_points", finalPosition: null })],
        qualifyingTotals: [],
      });

      const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);

      expect(result.get("ss-1")?.[0]).toMatchObject({ earnedPoints: null, currentQP: null });
    });
  });

  describe("qualifying_points pattern — finalized (has finalPosition)", () => {
    it("returns earnedPoints via calculateFantasyPoints when finalPosition set", async () => {
      const db = makeDb({
        picks: [makePick({ id: "p-1", sportsSeasonId: "ss-1", scoringPattern: "qualifying_points", finalPosition: 2 })],
        qualifyingTotals: [{ participantId: "p-1", totalQualifyingPoints: "99" }],
      });

      const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);

      expect(result.get("ss-1")?.[0]).toMatchObject({
        earnedPoints: 75, // pointsFor2nd
        currentQP: null,
      });
    });

    it("splits earnedPoints for tied QP placements", async () => {
      const db = makeDb({
        picks: [makePick({ id: "p-1", sportsSeasonId: "ss-1", scoringPattern: "qualifying_points", finalPosition: 2 })],
        qualifyingTotals: [{ participantId: "p-1", totalQualifyingPoints: "99" }],
        seasonParticipantResults: [
          { sportsSeasonId: "ss-1", finalPosition: 2 },
          { sportsSeasonId: "ss-1", finalPosition: 2 },
        ],
      });

      const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);

      expect(result.get("ss-1")?.[0]).toMatchObject({
        earnedPoints: 62.5, // (75 + 50) / 2
        currentQP: null,
      });
    });
  });

  describe("season_standings pattern", () => {
    it("returns earnedPoints via calculateFantasyPoints", async () => {
      const db = makeDb({
        picks: [makePick({ id: "p-1", sportsSeasonId: "ss-1", scoringPattern: "season_standings", finalPosition: 3 })],
      });

      const result = await getDraftedParticipantsWithPoints("team-1", "season-1", db);

      expect(result.get("ss-1")?.[0]).toMatchObject({
        earnedPoints: 50, // pointsFor3rd
        currentQP: null,
      });
    });
  });

  it("does not query scoringEvents when no playoff_bracket picks", async () => {
    const db = makeDb({
      picks: [makePick({ scoringPattern: "season_standings", finalPosition: 1 })],
    });

    await getDraftedParticipantsWithPoints("team-1", "season-1", db);

    expect(db.query.scoringEvents.findMany).not.toHaveBeenCalled();
  });

  it("does not query participantQualifyingTotals when no qualifying_points picks", async () => {
    const db = makeDb({
      picks: [makePick({ scoringPattern: "playoff_bracket", finalPosition: null })],
      scoringEvents: [{ sportsSeasonId: "ss-1", bracketTemplateId: null }],
    });

    await getDraftedParticipantsWithPoints("team-1", "season-1", db);

    expect(db.query.seasonParticipantQualifyingTotals.findMany).not.toHaveBeenCalled();
  });
});
