/**
 * PIFF 3.0 Player Prop Loader for Twitter Bot
 *
 * Adapted from Rainmaker's piff.ts. Reads today's PIFF 3.0 pick files and
 * exposes props by team abbreviation. Includes team-name reverse lookup
 * (full name -> abbreviation) for matching enriched game data to PIFF teams.
 *
 * PIFF 3.0: Direction-agnostic (overs + unders), DVP primary filter, H2H, tiers.
 */

import fs from 'fs';
import path from 'path';

const PICKS_DIR = '/home/administrator/.openclaw/agents/sportsclaw/workspace/picks';
const TEAM_NAMES_PATH = path.resolve(__dirname, '../seo/team-names.json');

// ── PIFF Leg Interface ──────────────────────────────────────

export interface PiffLeg {
  name: string;
  team: string;
  stat: string;
  line: number;
  edge: number;
  prob: number;
  direction?: string;     // 'over' or 'under' (3.0)
  tier?: number;          // 1=LOCK, 2=STRONG, 3=SOLID (3.0)
  tier_label?: string;    // T1_LOCK, T2_STRONG, T3_SOLID (3.0)
  dvp_adj?: number;
  dvp_rank?: number;
  dvp_tier?: string;      // EASY, AVG, ELITE (3.0)
  dvp?: number;
  h2h_games?: number;
  h2h_hr?: number;
  h2h_flag?: string;
  opponent?: string;
  is_home?: boolean;
  szn_hr?: number;
  l5_hr?: number;
  l10_hr?: number;
  gap?: number;
  league?: string;
}

interface PiffFile {
  date: string;
  legs: PiffLeg[];
}

// ── File Loading ────────────────────────────────────────────

function loadPiffFile(filePath: string): PiffLeg[] {
  try {
    if (!fs.existsSync(filePath)) return [];
    const raw = fs.readFileSync(filePath, 'utf-8');
    const data: PiffFile = JSON.parse(raw);
    return data.legs || [];
  } catch (err) {
    console.error(`[piff-loader] Failed to load PIFF file ${filePath}:`, err);
    return [];
  }
}

function getTodayET(): string {
  const now = new Date();
  const et = new Date(now.toLocaleString('en-US', { timeZone: 'America/New_York' }));
  const y = et.getFullYear();
  const m = String(et.getMonth() + 1).padStart(2, '0');
  const d = String(et.getDate()).padStart(2, '0');
  return `${y}-${m}-${d}`;
}

const PIFF_LEAGUES = [
  'nba', 'ncaab', 'nhl',
  'epl', 'la_liga', 'bundesliga', 'serie_a', 'ligue_1', 'champions_league',
];

const SOCCER_LEAGUES = new Set(['epl', 'la_liga', 'bundesliga', 'serie_a', 'ligue_1', 'champions_league']);

// ── Team Name Reverse Lookup ────────────────────────────────

let reverseMap: Map<string, string> | null = null;

/**
 * Build fullName -> abbreviation map from team-names.json.
 * team-names.json maps abbreviation -> fullName, so we invert it.
 * Only keeps short abbreviations (<=6 chars) as keys to avoid
 * mapping fullName->fullName identity entries.
 */
function buildReverseMap(): Map<string, string> {
  if (reverseMap) return reverseMap;
  reverseMap = new Map();

  try {
    if (!fs.existsSync(TEAM_NAMES_PATH)) {
      console.warn('[piff-loader] team-names.json not found');
      return reverseMap;
    }
    const data: Record<string, string> = JSON.parse(fs.readFileSync(TEAM_NAMES_PATH, 'utf-8'));

    for (const [abbrev, fullName] of Object.entries(data)) {
      // Only use short abbreviations (2-6 chars) as source keys
      if (abbrev.length > 6) continue;
      const normFull = fullName.toLowerCase().trim();
      // Don't overwrite if we already have a shorter abbreviation
      if (!reverseMap.has(normFull) || abbrev.length < (reverseMap.get(normFull)?.length ?? Infinity)) {
        reverseMap.set(normFull, abbrev.toUpperCase());
      }
    }
    console.log(`[piff-loader] Built reverse team map: ${reverseMap.size} entries`);
  } catch (e) {
    console.warn('[piff-loader] Failed to build reverse team map:', (e as Error).message);
  }

  return reverseMap;
}

/**
 * Get the team abbreviation for a full team name.
 * Returns the input as-is (uppercased) if no mapping found.
 * For soccer leagues, returns the full name since PIFF uses full names.
 */
export function getTeamAbbrev(fullName: string, league?: string): string {
  // Soccer PIFF uses full team names, not abbreviations
  if (league && SOCCER_LEAGUES.has(league.toLowerCase())) {
    return fullName;
  }

  // If it's already short (<=6 chars), it's probably already an abbreviation
  if (fullName.length <= 6) return fullName.toUpperCase();

  const map = buildReverseMap();
  const norm = fullName.toLowerCase().trim();

  // Try exact match
  if (map.has(norm)) return map.get(norm)!;

  // Try without common suffixes (e.g. "Houston Rockets" -> "Houston")
  const words = norm.split(/\s+/);
  if (words.length >= 2) {
    // Try first word (city name)
    for (const [key, abbrev] of map) {
      if (key.startsWith(words[0]) || key.includes(norm)) {
        return abbrev;
      }
    }
  }

  // Fallback: return uppercase of input
  return fullName.toUpperCase();
}

// ── PIFF Loading with Cache ─────────────────────────────────

let cachedPiffMap: Record<string, PiffLeg[]> | null = null;
let cachedPiffDate: string | null = null;

/**
 * Load all PIFF 3.0 props for today, cached per date.
 * Reloads when the ET date changes (i.e. once per day).
 */
export function getPiffMapCached(): Record<string, PiffLeg[]> {
  const today = getTodayET();
  if (cachedPiffMap && cachedPiffDate === today) {
    return cachedPiffMap;
  }

  cachedPiffMap = loadTodaysPiffProps();
  cachedPiffDate = today;
  return cachedPiffMap;
}

/**
 * Force-refresh the PIFF cache (call at start of each worker cycle).
 */
export function refreshPiffCache(): void {
  cachedPiffMap = null;
  cachedPiffDate = null;
}

/**
 * Load all PIFF 3.0 props for today, indexed by uppercase team abbreviation.
 */
export function loadTodaysPiffProps(): Record<string, PiffLeg[]> {
  const today = getTodayET();
  const map: Record<string, PiffLeg[]> = {};
  let totalLegs = 0;

  // Load unified PIFF 3.0 files for all leagues
  for (const league of PIFF_LEAGUES) {
    const legs = loadPiffFile(path.join(PICKS_DIR, `piff30_${league}_${today}.json`));
    for (const leg of legs) {
      const key = leg.team.toUpperCase();
      if (!map[key]) map[key] = [];
      map[key].push(leg);
      totalLegs++;
    }
  }

  // Fallback: legacy NBA-only file
  if (!map['ATL'] && !map['LAL']) {
    const legacyNba = loadPiffFile(path.join(PICKS_DIR, `piff30_${today}.json`));
    for (const leg of legacyNba) {
      const key = leg.team.toUpperCase();
      if (!map[key]) map[key] = [];
      map[key].push(leg);
      totalLegs++;
    }
  }

  // Fallback: legacy piff27 files
  if (totalLegs === 0) {
    for (const suffix of ['nhl', 'soccer']) {
      const legs = loadPiffFile(path.join(PICKS_DIR, `piff27_${suffix}_${today}.json`));
      for (const leg of legs) {
        const key = leg.team.toUpperCase();
        if (!map[key]) map[key] = [];
        map[key].push(leg);
        totalLegs++;
      }
    }
  }

  console.log(`[piff-loader] Loaded ${totalLegs} props across ${Object.keys(map).length} teams for ${today}`);
  return map;
}

/**
 * Get PIFF props relevant to a specific game by matching team abbreviations.
 */
export function getPiffPropsForGame(
  homeShort: string,
  awayShort: string,
  piffMap?: Record<string, PiffLeg[]>
): PiffLeg[] {
  const map = piffMap || getPiffMapCached();
  const homeKey = homeShort.toUpperCase();
  const awayKey = awayShort.toUpperCase();

  const homeProps = map[homeKey] || [];
  const awayProps = map[awayKey] || [];

  return [...homeProps, ...awayProps];
}

/**
 * Format PIFF props into a prompt section for Grok.
 */
export function formatPiffForPrompt(props: PiffLeg[]): string {
  if (props.length === 0) return '';

  const lines = props.map(p => {
    const edgePct = (p.edge * 100).toFixed(1);
    const hrPct = p.szn_hr ? (p.szn_hr * 100).toFixed(0) : '?';
    const dir = p.direction ? p.direction.charAt(0).toUpperCase() : 'O';
    const tierStr = p.tier_label ? ` [${p.tier_label}]` : '';
    const dvpStr = p.dvp_tier ? ` DVP: ${p.dvp_tier}` : '';
    const h2hStr = p.h2h_games && p.h2h_games >= 3 ? ` H2H: ${((p.h2h_hr ?? 0) * 100).toFixed(0)}%(${p.h2h_games}g)` : '';
    const gapStr = p.gap ? ` gap:${p.gap.toFixed(1)}` : '';
    return `- ${p.name} ${dir}${p.line} ${p.stat}${tierStr} (HR:${hrPct}%${gapStr}, edge:+${edgePct}%${dvpStr}${h2hStr})`;
  });

  return `\nPIFF 3.0 PLAYER PROP MODEL (direction-agnostic, CLV-tracked, 78% hit rate):\n${lines.join('\n')}\nThese props are quantitatively modeled. Prioritize PIFF T1_LOCK and T2_STRONG legs when making prop recommendations.`;
}

/**
 * Get all T1_LOCK and T2_STRONG legs from today's PIFF, sorted by edge descending.
 */
export function getTopPiffLegs(maxLegs: number = 10): PiffLeg[] {
  const map = getPiffMapCached();
  const allLegs: PiffLeg[] = [];

  for (const legs of Object.values(map)) {
    for (const leg of legs) {
      if (leg.tier_label === 'T1_LOCK' || leg.tier_label === 'T2_STRONG') {
        allLegs.push(leg);
      }
    }
  }

  // Sort by edge descending
  allLegs.sort((a, b) => b.edge - a.edge);
  return allLegs.slice(0, maxLegs);
}
