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

const SCHEME_TYPES = ['DROP', 'SWITCH', 'HEDGE', 'MIXED', 'UNKNOWN'];
const MIN_POSSESSIONS = 8;
const CACHE_TTL = 21600; // 6 hours in seconds
const NBA_STATS_BASE = process.env.NBA_STATS_URL || 'http://localhost:8000';
const PYTHON_SERVICE_BASE = process.env.PYTHON_SERVICE_URL || 'http://localhost:5001';

/**
 * Get cache key for scheme classification.
 * Keyed per opponent per game day.
 */
function getCacheKey(opponentTeam, gameDate) {
  return `scheme:${opponentTeam}:${gameDate}`;
}

/**
 * Fetch play-by-play data for a team's last 5 games.
 * Returns raw possession data for PnR analysis.
 */
async function fetchPlayByPlay(teamAbbr) {
  const url = `${NBA_STATS_BASE}/team/playbyplay`;
  const response = await axios.get(url, {
    params: { team: teamAbbr, last_n_games: 5 },
    timeout: 15000,
  });
  return response.data;
}

/**
 * Extract pick-and-roll defensive possessions from play-by-play data.
 * Looks for PnR ball handler and roll man actions in the play descriptions.
 */
function extractPnRPossessions(plays) {
  if (!Array.isArray(plays)) return [];

  const pnrIndicators = [
    /pick.?and.?roll/i,
    /screen.*roll/i,
    /ball.?screen/i,
    /pnr/i,
    /hedge/i,
    /drop.*coverage/i,
    /switch.*screen/i,
    /ice.*screen/i,
    /blitz.*screen/i,
    /trap.*screen/i,
  ];

  return plays.filter((play) => {
    const desc = play.description || play.play_description || '';
    return pnrIndicators.some((pattern) => pattern.test(desc));
  });
}

/**
 * Classify the defensive coverage scheme from PnR possessions.
 * Requires minimum 8 possessions to produce a classification.
 */
function classifyScheme(pnrPossessions) {
  if (!pnrPossessions || pnrPossessions.length < MIN_POSSESSIONS) {
    return { scheme: 'UNKNOWN', confidence: 0, possessions_analyzed: pnrPossessions ? pnrPossessions.length : 0, reason: 'insufficient_data' };
  }

  const counts = { DROP: 0, SWITCH: 0, HEDGE: 0 };

  for (const poss of pnrPossessions) {
    const desc = (poss.description || poss.play_description || '').toLowerCase();

    if (/drop|sag|contain|soft/i.test(desc)) {
      counts.DROP++;
    } else if (/switch|swap/i.test(desc)) {
      counts.SWITCH++;
    } else if (/hedge|blitz|trap|hard.*show|ice/i.test(desc)) {
      counts.HEDGE++;
    }
  }

  const total = counts.DROP + counts.SWITCH + counts.HEDGE;
  if (total === 0) {
    return { scheme: 'UNKNOWN', confidence: 0, possessions_analyzed: pnrPossessions.length, reason: 'no_classifiable_actions' };
  }

  const dominant = Object.entries(counts).sort((a, b) => b[1] - a[1]);
  const topScheme = dominant[0][0];
  const topCount = dominant[0][1];
  const dominance = topCount / total;

  // MIXED if no scheme exceeds 55% dominance
  if (dominance < 0.55) {
    return {
      scheme: 'MIXED',
      confidence: Math.round(dominance * 100),
      possessions_analyzed: pnrPossessions.length,
      breakdown: counts,
    };
  }

  return {
    scheme: topScheme,
    confidence: Math.round(dominance * 100),
    possessions_analyzed: pnrPossessions.length,
    breakdown: counts,
  };
}

/**
 * Fetch defensive scheme from Python Synergy service.
 * Returns full defensive play type distribution when available.
 * Falls back to null if Synergy service is unavailable.
 */
async function fetchSynergyScheme(teamId) {
  try {
    const url = `${PYTHON_SERVICE_BASE}/api/synergy/defensive-scheme/${teamId}`;
    const response = await axios.get(url, { timeout: 10000 });
    const data = response.data;
    if (data && data.defensive_distribution) {
      return {
        scheme: classifyFromDistribution(data.defensive_distribution),
        distribution: data.defensive_distribution,
        source: 'synergy',
      };
    }
    return null;
  } catch (e) {
    // Synergy unavailable — fallback to regex
    console.warn('[VYNDR] Synergy scheme fetch unavailable:', e.message);
    return null;
  }
}

/**
 * Classify scheme from Synergy defensive play type distribution.
 * Maps play type frequencies to scheme classification.
 */
function classifyFromDistribution(distribution) {
  if (!distribution || Object.keys(distribution).length === 0) return 'UNKNOWN';

  const pnrHandler = distribution['PRBallHandler'] || {};
  const pnrRollman = distribution['PRRollman'] || {};
  const isolation = distribution['Isolation'] || {};

  const pnrFreq = (pnrHandler.frequency_pct || 0) + (pnrRollman.frequency_pct || 0);
  if (pnrFreq < 0.05) return 'UNKNOWN'; // too little PnR data

  // High PPP allowed on PnR = likely DROP (giving up mid-range)
  // Low PPP on PnR = likely SWITCH or HEDGE (disrupting)
  const pnrPPP = pnrHandler.ppp || 0;
  const pnrTO = pnrHandler.to_pct || 0;

  if (pnrPPP > 0.95 && pnrTO < 0.10) return 'DROP';
  if (pnrPPP < 0.80 && pnrTO > 0.15) return 'HEDGE';
  if (isolation.frequency_pct > 0.15) return 'SWITCH'; // switch-heavy teams force isolations

  return 'MIXED';
}

/**
 * Get scheme classification for an opponent.
 * Tries Synergy first, falls back to play-by-play regex.
 * Checks cache first. Graceful degradation: returns UNKNOWN if all sources unavailable.
 */
async function getSchemeClassification(opponentTeam, gameDate) {
  const redis = getRedisClient();
  const cacheKey = getCacheKey(opponentTeam, gameDate || new Date().toISOString().split('T')[0]);

  // Check cache
  try {
    const cached = await redis.get(cacheKey);
    if (cached) {
      return { ...JSON.parse(cached), source: 'cache' };
    }
  } catch (e) {
    // Redis failure is non-fatal
    console.warn('[VYNDR] Scheme cache read error:', e.message);
  }

  // Try Synergy service first (enhanced path)
  try {
    const synergyResult = await fetchSynergyScheme(opponentTeam);
    if (synergyResult) {
      const result = {
        opponent: opponentTeam,
        game_date: gameDate || new Date().toISOString().split('T')[0],
        ...synergyResult,
        classified_at: new Date().toISOString(),
      };
      try { await redis.set(cacheKey, JSON.stringify(result), 'EX', CACHE_TTL); } catch (e) { /* non-fatal */ }
      return { ...result, source: 'synergy' };
    }
  } catch (e) {
    console.warn('[VYNDR] Synergy fallthrough to regex:', e.message);
  }

  // Fallback to play-by-play regex classification
  try {
    const pbpData = await fetchPlayByPlay(opponentTeam);
    const plays = pbpData.plays || pbpData.play_by_play || [];
    const pnrPossessions = extractPnRPossessions(plays);
    const classification = classifyScheme(pnrPossessions);

    const result = {
      opponent: opponentTeam,
      game_date: gameDate || new Date().toISOString().split('T')[0],
      ...classification,
      classified_at: new Date().toISOString(),
    };

    // Cache the result
    try {
      await redis.set(cacheKey, JSON.stringify(result), 'EX', CACHE_TTL);
    } catch (e) {
      console.warn('[VYNDR] Scheme cache write error:', e.message);
    }

    return { ...result, source: 'live' };
  } catch (e) {
    // Graceful degradation — grade still produces even if this service is down
    console.warn('[VYNDR] Scheme classifier unavailable:', e.message);
    return {
      opponent: opponentTeam,
      game_date: gameDate || new Date().toISOString().split('T')[0],
      scheme: 'UNKNOWN',
      confidence: 0,
      possessions_analyzed: 0,
      reason: 'api_unavailable',
      source: 'fallback',
    };
  }
}

/**
 * Log scheme classification to model_predictions_extended table.
 * Phase 1: Data collection only. Not user-visible.
 * User-visible activation happens Day 31.
 */
async function logSchemeToExtended(predictionId, schemeResult, supabaseClient) {
  if (!supabaseClient || !predictionId) return;

  try {
    const { error } = await supabaseClient
      .from('model_predictions_extended')
      .update({
        active_role_tonight: `scheme:${schemeResult.scheme}`,
        model_version: '1.0-scheme',
      })
      .eq('prediction_id', predictionId);

    if (error) {
      console.warn('[VYNDR] Scheme log write error:', error.message);
    }
  } catch (e) {
    // Non-fatal — silent logging only
    console.warn('[VYNDR] Scheme log error:', e.message);
  }
}

module.exports = {
  SCHEME_TYPES,
  MIN_POSSESSIONS,
  CACHE_TTL,
  getCacheKey,
  fetchPlayByPlay,
  fetchSynergyScheme,
  classifyFromDistribution,
  extractPnRPossessions,
  classifyScheme,
  getSchemeClassification,
  logSchemeToExtended,
};
