import type { BacktestSummary, BacktestTimeframe, EquityPoint } from '../types.js';

const minutesByTimeframe: Record<BacktestTimeframe, number> = {
    '1m': 1,
    '15m': 15,
    '1h': 60,
    '4h': 240
};

const round = (value: number, precision: number = 6): number => {
    const factor = Math.pow(10, precision);
    return Math.round(value * factor) / factor;
};

const stdDev = (values: number[]): number => {
    if (!values.length) return 0;
    const mean = values.reduce((sum, value) => sum + value, 0) / values.length;
    const variance = values.reduce((sum, value) => sum + Math.pow(value - mean, 2), 0) / values.length;
    return Math.sqrt(variance);
};

export const computeSharpe = (timeline: EquityPoint[], timeframe: BacktestTimeframe): number => {
    if (timeline.length < 2) return 0;
    const returns: number[] = [];
    for (let i = 1; i < timeline.length; i++) {
        const prev = timeline[i - 1].equityUsd;
        const next = timeline[i].equityUsd;
        if (prev <= 0) continue;
        returns.push((next - prev) / prev);
    }
    if (!returns.length) return 0;
    const mean = returns.reduce((sum, value) => sum + value, 0) / returns.length;
    const sigma = stdDev(returns);
    if (sigma === 0) return 0;
    const periodsPerYear = (365 * 24 * 60) / minutesByTimeframe[timeframe];
    return round((mean / sigma) * Math.sqrt(periodsPerYear), 6);
};

export const computeSummary = (
    trades: Array<{ pnlUsd: number }>,
    timeline: EquityPoint[],
    timeframe: BacktestTimeframe
): BacktestSummary => {
    const totalTrades = trades.length;
    const netPnlUsd = trades.reduce((sum, trade) => sum + Number(trade.pnlUsd || 0), 0);
    const winningTrades = trades.filter((trade) => Number(trade.pnlUsd || 0) > 0).length;
    const winRate = totalTrades > 0 ? (winningTrades / totalTrades) * 100 : 0;
    const maxDrawdownPct = timeline.length > 0
        ? timeline.reduce((max, point) => Math.max(max, Number(point.drawdownPct || 0)), 0)
        : 0;
    const sharpe = computeSharpe(timeline, timeframe);

    return {
        netPnlUsd: round(netPnlUsd, 8),
        winRate: round(winRate, 6),
        maxDrawdownPct: round(maxDrawdownPct, 6),
        sharpe,
        totalTrades
    };
};
