const { getSupabaseServiceClient } = require('../utils/supabase');
const { getRedisClient } = require('../utils/redis');

function getToday() {
  return new Date().toISOString().split('T')[0];
}

async function processNewOdds(sport, props) {
  const supabase = getSupabaseServiceClient();
  const redis = getRedisClient();
  const today = getToday();
  const baselineKey = `odds:baseline_set:${sport}:${today}`;

  // Check if baseline exists for today
  const hasBaseline = await redis.get(baselineKey);

  if (!hasBaseline) {
    // First fetch of the day — capture baseline
    await captureBaseline(supabase, sport, today, props);
    await redis.set(baselineKey, '1', 'EX', 86400);
    return { movements: [], isBaselineCapture: true };
  }

  // Compare current lines to baseline
  const movements = await detectMovements(supabase, sport, today, props);
  return { movements, isBaselineCapture: false };
}

async function captureBaseline(supabase, sport, today, props) {
  const rows = props.map((p) => ({
    sport,
    game_date: today,
    player: p.player,
    stat_type: p.stat_type,
    book: p.book,
    baseline_line: p.line,
  }));

  if (rows.length === 0) return;

  // Upsert to handle re-captures (unique index prevents duplicates)
  await supabase.from('line_baselines').upsert(rows, {
    onConflict: 'game_date,player,stat_type,book',
  });

  // Cleanup old baselines
  await supabase.from('line_baselines').delete().lt('game_date', getOldDate());
  await supabase.from('line_movements').delete().lt('game_date', getOldDate());
}

async function detectMovements(supabase, sport, today, props) {
  // Fetch today's baselines
  const { data: baselines } = await supabase
    .from('line_baselines')
    .select('*')
    .eq('game_date', today);

  if (!baselines || baselines.length === 0) return [];

  // Build lookup
  const baselineMap = {};
  for (const b of baselines) {
    baselineMap[`${b.player}::${b.stat_type}::${b.book}`] = b;
  }

  const movements = [];
  for (const prop of props) {
    const key = `${prop.player}::${prop.stat_type}::${prop.book}`;
    const baseline = baselineMap[key];
    if (!baseline) continue;

    const diff = prop.line - baseline.baseline_line;
    if (Math.abs(diff) < 0.5) continue;

    const direction = diff > 0 ? 'up' : 'down';
    const sharpIndicator = determineSharpIndicator(
      baseline.baseline_line, prop.line, prop.over_odds, prop.under_odds, direction
    );

    const movement = {
      sport,
      game_date: today,
      player: prop.player,
      stat_type: prop.stat_type,
      book: prop.book,
      baseline_line: baseline.baseline_line,
      current_line: prop.line,
      movement: Math.round(Math.abs(diff) * 10) / 10,
      direction,
      sharp_indicator: sharpIndicator,
    };

    movements.push(movement);
  }

  // Store movements in DB
  if (movements.length > 0) {
    await supabase.from('line_movements').insert(movements);
  }

  return movements;
}

function determineSharpIndicator(baselineLine, currentLine, overOdds, underOdds, direction) {
  // Heuristic: if line moves up (higher) and over odds get worse (more negative),
  // sharps are on the under. If line moves down and under odds get worse, sharps on over.
  if (overOdds == null || underOdds == null) return 'unknown';

  if (direction === 'up') {
    // Line went up — if over is expensive (< -115), sharps may be on under
    if (overOdds < -115) return 'sharp_action';
    if (underOdds < -115) return 'public_action';
  } else {
    // Line went down — if under is expensive, sharps may be on over
    if (underOdds < -115) return 'sharp_action';
    if (overOdds < -115) return 'public_action';
  }

  return 'unknown';
}

function getOldDate() {
  const d = new Date();
  d.setUTCDate(d.getUTCDate() - 2);
  return d.toISOString().split('T')[0];
}

async function getMovementsForToday(sport, filters = {}) {
  const supabase = getSupabaseServiceClient();
  const today = getToday();

  let query = supabase
    .from('line_movements')
    .select('*')
    .eq('game_date', today);

  if (filters.player) {
    query = query.ilike('player', `%${filters.player}%`);
  }
  if (filters.stat_type) {
    query = query.eq('stat_type', filters.stat_type);
  }

  const { data: movements } = await query;

  let filtered = movements || [];
  if (filters.min_movement) {
    filtered = filtered.filter((m) => m.movement >= filters.min_movement);
  }

  return filtered;
}

module.exports = {
  processNewOdds,
  captureBaseline,
  detectMovements,
  determineSharpIndicator,
  getMovementsForToday,
};
