import { database } from "~/database/context";
import * as schema from "~/database/schema";
import { eq } from "drizzle-orm";
import { DEFAULT_SCORING_RULES, type ScoringRules } from "~/lib/scoring-types";

// Re-export for convenience
export { DEFAULT_SCORING_RULES, type ScoringRules };

/**
 * Get scoring rules for a season
 */
export async function getScoringRules(
  seasonId: string,
  providedDb?: ReturnType<typeof database>
): Promise<ScoringRules | null> {
  const db = providedDb || database();

  const season = await db.query.seasons.findFirst({
    where: eq(schema.seasons.id, seasonId),
  });

  if (!season) {
    return null;
  }

  return {
    pointsFor1st: season.pointsFor1st,
    pointsFor2nd: season.pointsFor2nd,
    pointsFor3rd: season.pointsFor3rd,
    pointsFor4th: season.pointsFor4th,
    pointsFor5th: season.pointsFor5th,
    pointsFor6th: season.pointsFor6th,
    pointsFor7th: season.pointsFor7th,
    pointsFor8th: season.pointsFor8th,
  };
}

/**
 * Update scoring rules for a season
 */
export async function updateScoringRules(
  seasonId: string,
  rules: Partial<ScoringRules>,
  providedDb?: ReturnType<typeof database>
): Promise<ScoringRules> {
  const db = providedDb || database();

  const [updated] = await db
    .update(schema.seasons)
    .set(rules)
    .where(eq(schema.seasons.id, seasonId))
    .returning({
      pointsFor1st: schema.seasons.pointsFor1st,
      pointsFor2nd: schema.seasons.pointsFor2nd,
      pointsFor3rd: schema.seasons.pointsFor3rd,
      pointsFor4th: schema.seasons.pointsFor4th,
      pointsFor5th: schema.seasons.pointsFor5th,
      pointsFor6th: schema.seasons.pointsFor6th,
      pointsFor7th: schema.seasons.pointsFor7th,
      pointsFor8th: schema.seasons.pointsFor8th,
    });

  return updated;
}

/**
 * Calculate fantasy points for a given placement based on season scoring rules
 */
export function calculateFantasyPoints(
  placement: number,
  rules: ScoringRules
): number {
  const pointsMap: Record<number, number> = {
    1: rules.pointsFor1st,
    2: rules.pointsFor2nd,
    3: rules.pointsFor3rd,
    4: rules.pointsFor4th,
    5: rules.pointsFor5th,
    6: rules.pointsFor6th,
    7: rules.pointsFor7th,
    8: rules.pointsFor8th,
  };

  return pointsMap[placement] || 0;
}

/**
 * Calculate averaged points for shared placements (e.g., playoff ties)
 * Used when multiple participants share positions
 *
 * Example: 4 teams lose in quarterfinals, they share positions 5-8
 * Average = (25 + 25 + 15 + 15) / 4 = 20 points each
 */
export function calculateAveragedPoints(
  placements: number[],
  rules: ScoringRules
): number {
  if (placements.length === 0) return 0;

  const total = placements.reduce((sum, placement) => {
    return sum + calculateFantasyPoints(placement, rules);
  }, 0);

  return total / placements.length;
}

/**
 * Tier definitions for brackets where positions 5–8 split into two separate pairs.
 *
 * Most brackets (standard single-elimination) have ONE tier covering positions 5–8:
 * four QF losers all tie and share the combined prize pool → avg([5,6,7,8]).
 *
 * AFL is different: it has TWO distinct tiers in the 5–8 zone:
 *   - T5-T6: Semi-Finals losers (positions 5 and 6) → avg([5,6])
 *   - T7-T8: Elimination Finals losers (positions 7 and 8) → avg([7,8])
 */
const SPLIT_5678_TEMPLATE_IDS = new Set(["afl_10"]);

/**
 * Calculate fantasy points for a bracket placement, averaging tied positions.
 *
 * Standard single-elimination bracket tiers:
 *   1st: solo winner
 *   2nd: solo finalist
 *   3rd-4th: two SF losers share these positions → averaged
 *   5th-8th: four QF losers share these positions → averaged
 *
 * AFL bracket tiers (afl_10):
 *   5th-6th: Semi-Finals losers → averaged separately from 7th-8th
 *   7th-8th: Elimination Finals losers → averaged separately from 5th-6th
 *
 * Use this instead of calculateFantasyPoints for playoff_bracket scoring.
 */
export function calculateBracketPoints(
  finalPosition: number,
  rules: ScoringRules,
  bracketTemplateId?: string | null
): number {
  if (finalPosition <= 0) return 0;
  if (finalPosition === 1) return rules.pointsFor1st;
  if (finalPosition === 2) return rules.pointsFor2nd;
  if (finalPosition === 3 || finalPosition === 4)
    return calculateAveragedPoints([3, 4], rules);
  if (finalPosition >= 5 && finalPosition <= 8) {
    if (bracketTemplateId && SPLIT_5678_TEMPLATE_IDS.has(bracketTemplateId)) {
      // AFL-style: two separate 2-team tiers within 5–8
      if (finalPosition <= 6) return calculateAveragedPoints([5, 6], rules);
      return calculateAveragedPoints([7, 8], rules);
    }
    // Standard: all four QF losers share one tier
    return calculateAveragedPoints([5, 6, 7, 8], rules);
  }
  return 0;
}

/**
 * Get points array as a simple ordered list [1st, 2nd, 3rd, ..., 8th]
 * Useful for display purposes
 */
export function getScoringRulesArray(rules: ScoringRules): number[] {
  return [
    rules.pointsFor1st,
    rules.pointsFor2nd,
    rules.pointsFor3rd,
    rules.pointsFor4th,
    rules.pointsFor5th,
    rules.pointsFor6th,
    rules.pointsFor7th,
    rules.pointsFor8th,
  ];
}
