/**
 * Model for Participant Golf Skills
 *
 * Manages golf-specific skill data for qualifying-points golf seasons.
 * Primary metric: SG: Total (strokes gained per round vs. field average).
 * Optional per-major American odds allow major-specific probability blending.
 */

import { database } from "~/database/context";
import { participantGolfSkills, participants } from "~/database/schema";
import { eq, sql } from "drizzle-orm";

export interface GolfSkillsRecord {
  id: string;
  participantId: string;
  sportsSeasonId: string;
  sgTotal: number | null;
  datagolfRank: number | null;
  mastersOdds: number | null;
  usOpenOdds: number | null;
  openChampionshipOdds: number | null;
  pgaChampionshipOdds: number | null;
  updatedAt: Date;
}

export interface GolfSkillsWithName extends GolfSkillsRecord {
  participantName: string;
}

export interface GolfSkillsInput {
  participantId: string;
  sportsSeasonId: string;
  sgTotal?: number | null;
  datagolfRank?: number | null;
  mastersOdds?: number | null;
  usOpenOdds?: number | null;
  openChampionshipOdds?: number | null;
  pgaChampionshipOdds?: number | null;
}

/**
 * Get all golf skill records for a sports season, joined with participant names.
 * Returns one record per participant (participants with no record are excluded).
 */
export async function getGolfSkillsForSeason(
  sportsSeasonId: string
): Promise<GolfSkillsWithName[]> {
  const db = database();
  const rows = await db
    .select({
      id: participantGolfSkills.id,
      participantId: participantGolfSkills.participantId,
      sportsSeasonId: participantGolfSkills.sportsSeasonId,
      sgTotal: participantGolfSkills.sgTotal,
      datagolfRank: participantGolfSkills.datagolfRank,
      mastersOdds: participantGolfSkills.mastersOdds,
      usOpenOdds: participantGolfSkills.usOpenOdds,
      openChampionshipOdds: participantGolfSkills.openChampionshipOdds,
      pgaChampionshipOdds: participantGolfSkills.pgaChampionshipOdds,
      updatedAt: participantGolfSkills.updatedAt,
      participantName: participants.name,
    })
    .from(participantGolfSkills)
    .innerJoin(participants, eq(participantGolfSkills.participantId, participants.id))
    .where(eq(participantGolfSkills.sportsSeasonId, sportsSeasonId))
    .orderBy(participants.name);

  return rows.map((r) => ({
    ...r,
    sgTotal: r.sgTotal !== null ? Number(r.sgTotal) : null,
  }));
}

/**
 * Returns a Map from participantId → GolfSkillsRecord for use in the simulator.
 * Participants with no record are absent from the map (simulator falls back to SG = 0).
 */
export async function getGolfSkillsMap(
  sportsSeasonId: string
): Promise<Map<string, GolfSkillsRecord>> {
  const db = database();
  const rows = await db
    .select()
    .from(participantGolfSkills)
    .where(eq(participantGolfSkills.sportsSeasonId, sportsSeasonId));

  return new Map(rows.map((r) => [
    r.participantId,
    {
      ...r,
      sgTotal: r.sgTotal !== null ? Number(r.sgTotal) : null,
    },
  ]));
}

/**
 * Upsert golf skill ratings for a batch of participants.
 * Uses INSERT … ON CONFLICT DO UPDATE so all columns are overwritten atomically.
 */
export async function batchUpsertGolfSkills(
  inputs: GolfSkillsInput[]
): Promise<void> {
  if (inputs.length === 0) return;
  const db = database();
  const now = new Date();

  await db
    .insert(participantGolfSkills)
    .values(
      inputs.map(({
        participantId,
        sportsSeasonId,
        sgTotal,
        datagolfRank,
        mastersOdds,
        usOpenOdds,
        openChampionshipOdds,
        pgaChampionshipOdds,
      }) => ({
        participantId,
        sportsSeasonId,
        // decimal columns are stored/passed as strings in Drizzle
        sgTotal: sgTotal !== null && sgTotal !== undefined ? String(sgTotal) : null,
        datagolfRank: datagolfRank ?? null,
        mastersOdds: mastersOdds ?? null,
        usOpenOdds: usOpenOdds ?? null,
        openChampionshipOdds: openChampionshipOdds ?? null,
        pgaChampionshipOdds: pgaChampionshipOdds ?? null,
        updatedAt: now,
      }))
    )
    .onConflictDoUpdate({
      target: [participantGolfSkills.participantId, participantGolfSkills.sportsSeasonId],
      set: {
        sgTotal: sql`excluded.sg_total`,
        datagolfRank: sql`excluded.datagolf_rank`,
        mastersOdds: sql`excluded.masters_odds`,
        usOpenOdds: sql`excluded.us_open_odds`,
        openChampionshipOdds: sql`excluded.open_championship_odds`,
        pgaChampionshipOdds: sql`excluded.pga_championship_odds`,
        updatedAt: sql`excluded.updated_at`,
      },
    });
}
