/**
 * Performance Metrics Calculator
 * Calculates advanced metrics for backtesting results
 */

/**
 * Calculate Sharpe ratio
 * @param {number[]} returns - Array of returns (as percentages)
 * @param {number} riskFreeRate - Risk-free rate (default 0)
 * @returns {number} Sharpe ratio
 */
export function calculateSharpeRatio(returns, riskFreeRate = 0) {
  if (!returns || returns.length === 0) return 0;
  
  const avgReturn = returns.reduce((a, b) => a + b, 0) / returns.length;
  const stdDev = calculateStdDev(returns);
  
  if (stdDev === 0) return 0;
  
  // Annualized Sharpe ratio (assuming 252 trading days)
  return ((avgReturn - riskFreeRate) / stdDev) * Math.sqrt(252);
}

/**
 * Calculate standard deviation
 * @param {number[]} values - Array of values
 * @returns {number} Standard deviation
 */
function calculateStdDev(values) {
  if (values.length === 0) return 0;
  
  const avg = values.reduce((a, b) => a + b, 0) / values.length;
  const squareDiffs = values.map(value => Math.pow(value - avg, 2));
  const avgSquareDiff = squareDiffs.reduce((a, b) => a + b, 0) / values.length;
  
  return Math.sqrt(avgSquareDiff);
}

/**
 * Calculate maximum drawdown
 * @param {number[]} equityCurve - Array of equity values over time
 * @returns {number} Maximum drawdown as a percentage (0-1)
 */
export function calculateMaxDrawdown(equityCurve) {
  if (!equityCurve || equityCurve.length === 0) return 0;
  
  let maxDD = 0;
  let peak = equityCurve[0];
  
  for (let i = 1; i < equityCurve.length; i++) {
    if (equityCurve[i] > peak) {
      peak = equityCurve[i];
    }
    const drawdown = (peak - equityCurve[i]) / peak;
    if (drawdown > maxDD) {
      maxDD = drawdown;
    }
  }
  
  return maxDD;
}

/**
 * Calculate win/loss streaks
 * @param {Object[]} trades - Array of trade objects with isWin property
 * @returns {Object} Streak information
 */
export function calculateStreaks(trades) {
  if (!trades || trades.length === 0) {
    return { maxWinStreak: 0, maxLossStreak: 0, currentStreak: 0, currentStreakType: null };
  }
  
  let maxWinStreak = 0;
  let maxLossStreak = 0;
  let currentWinStreak = 0;
  let currentLossStreak = 0;
  
  for (const trade of trades) {
    if (trade.isWin) {
      currentWinStreak++;
      currentLossStreak = 0;
      if (currentWinStreak > maxWinStreak) {
        maxWinStreak = currentWinStreak;
      }
    } else {
      currentLossStreak++;
      currentWinStreak = 0;
      if (currentLossStreak > maxLossStreak) {
        maxLossStreak = currentLossStreak;
      }
    }
  }
  
  const lastTrade = trades[trades.length - 1];
  const currentStreak = lastTrade.isWin ? currentWinStreak : currentLossStreak;
  const currentStreakType = lastTrade.isWin ? 'win' : 'loss';
  
  return {
    maxWinStreak,
    maxLossStreak,
    currentStreak,
    currentStreakType
  };
}

/**
 * Calculate session-based performance
 * @param {Object[]} trades - Array of trade objects with session_bucket property
 * @returns {Object[]} Performance metrics by session
 */
export function calculateSessionPerformance(trades) {
  if (!trades || trades.length === 0) return [];
  
  const sessions = { PRE: [], RTH: [], POST: [] };
  
  trades.forEach(trade => {
    const session = trade.session_bucket || 'UNKNOWN';
    if (sessions[session]) {
      sessions[session].push(trade);
    }
  });
  
  return Object.keys(sessions).map(session => {
    const sessionTrades = sessions[session];
    if (sessionTrades.length === 0) return null;
    
    const wins = sessionTrades.filter(t => t.isWin).length;
    const losses = sessionTrades.filter(t => !t.isWin).length;
    const returns = sessionTrades.map(t => parseFloat(t.profitPct) || 0);
    const avgReturn = returns.length > 0 ? returns.reduce((a, b) => a + b, 0) / returns.length : 0;
    
    return {
      session,
      totalTrades: sessionTrades.length,
      wins,
      losses,
      winRate: sessionTrades.length > 0 ? (wins / sessionTrades.length) * 100 : 0,
      avgReturn,
      totalReturn: returns.reduce((a, b) => a + b, 0)
    };
  }).filter(Boolean);
}

/**
 * Find best/worst performing symbols
 * @param {Object[]} trades - Array of trade objects with symbol_norm and profitPct
 * @param {number} topN - Number of top/bottom symbols to return
 * @returns {Object} Best and worst performing symbols
 */
export function findBestWorstSymbols(trades, topN = 5) {
  if (!trades || trades.length === 0) {
    return { best: [], worst: [] };
  }
  
  const symbolStats = {};
  
  trades.forEach(trade => {
    const symbol = trade.symbol_norm || trade.symbol || 'UNKNOWN';
    if (!symbolStats[symbol]) {
      symbolStats[symbol] = {
        symbol,
        trades: [],
        totalReturn: 0,
        wins: 0,
        losses: 0
      };
    }
    
    const profitPct = parseFloat(trade.profitPct) || 0;
    symbolStats[symbol].trades.push(trade);
    symbolStats[symbol].totalReturn += profitPct;
    if (trade.isWin) {
      symbolStats[symbol].wins++;
    } else {
      symbolStats[symbol].losses++;
    }
  });
  
  const symbolArray = Object.values(symbolStats).map(stats => ({
    ...stats,
    avgReturn: stats.totalReturn / stats.trades.length,
    winRate: stats.trades.length > 0 ? (stats.wins / stats.trades.length) * 100 : 0
  }));
  
  const best = symbolArray
    .sort((a, b) => b.avgReturn - a.avgReturn)
    .slice(0, topN);
  
  const worst = symbolArray
    .sort((a, b) => a.avgReturn - b.avgReturn)
    .slice(0, topN);
  
  return { best, worst };
}

/**
 * Build equity curve from trades
 * @param {Object[]} trades - Array of trade objects with profitPct
 * @param {number} initialCapital - Starting capital (default 10000)
 * @returns {number[]} Equity curve values
 */
export function buildEquityCurve(trades, initialCapital = 10000) {
  if (!trades || trades.length === 0) return [initialCapital];
  
  const equityCurve = [initialCapital];
  let currentEquity = initialCapital;
  
  for (const trade of trades) {
    const profitPct = parseFloat(trade.profitPct) || 0;
    const profit = currentEquity * (profitPct / 100);
    currentEquity += profit;
    equityCurve.push(currentEquity);
  }
  
  return equityCurve;
}

