/**
 * Backtesting Service
 * API client for backtesting and historical predictions visualization via Express Proxy
 * ARCH-001: All ML and Data Service calls now go through authenticated Express gateway
 */

import { apiClient } from '@/lib/apiClient';

// ============================================================================
// Types
// ============================================================================

export interface OHLCVCandle {
  timestamp: string;
  open: number;
  high: number;
  low: number;
  close: number;
  volume: number;
  vwap?: number;
  trades?: number;
}

export interface CandlesResponse {
  symbol: string;
  timeframe: string;
  candles: OHLCVCandle[];
  count: number;
}

export interface PredictionPoint {
  timestamp: string;
  predicted_high: number;
  predicted_low: number;
  actual_high: number;
  actual_low: number;
  delta_high_predicted: number;
  delta_low_predicted: number;
  delta_high_actual: number;
  delta_low_actual: number;
  confidence_high: number;
  confidence_low: number;
  direction: 'long' | 'short' | 'neutral';
  signal_score: number;
}

export interface TradeSignal {
  timestamp: string;
  type: 'entry' | 'exit';
  direction: 'buy' | 'sell';
  price: number;
  stop_loss?: number;
  take_profit?: number;
  confidence: number;
  strategy: string;
  outcome?: 'win' | 'loss' | 'open';
  pnl?: number;
  pnl_percent?: number;
}

export interface BacktestTrade {
  id: string;
  entry_time: string;
  exit_time?: string;
  symbol: string;
  direction: 'long' | 'short';
  entry_price: number;
  exit_price?: number;
  stop_loss: number;
  take_profit: number;
  quantity: number;
  pnl?: number;
  pnl_percent?: number;
  status: 'open' | 'closed_tp' | 'closed_sl' | 'closed_manual';
  strategy: string;
  confidence: number;
  holding_time_minutes?: number;
}

export interface BacktestMetrics {
  total_trades: number;
  winning_trades: number;
  losing_trades: number;
  win_rate: number;
  profit_factor: number;
  gross_profit: number;
  gross_loss: number;
  net_profit: number;
  net_profit_percent: number;
  avg_win: number;
  avg_loss: number;
  avg_trade: number;
  largest_win: number;
  largest_loss: number;
  max_drawdown: number;
  max_drawdown_percent: number;
  max_consecutive_wins: number;
  max_consecutive_losses: number;
  sharpe_ratio: number;
  sortino_ratio: number;
  calmar_ratio: number;
  avg_holding_time_minutes: number;
  trading_days: number;
}

export interface EquityPoint {
  timestamp: string;
  equity: number;
  drawdown: number;
  drawdown_percent: number;
}

export interface StrategyPerformance {
  strategy: string;
  trades: number;
  win_rate: number;
  profit_factor: number;
  net_profit: number;
  avg_confidence: number;
}

export interface BacktestResult {
  symbol: string;
  timeframe: string;
  start_date: string;
  end_date: string;
  initial_capital: number;
  final_capital: number;
  trades: BacktestTrade[];
  metrics: BacktestMetrics;
  equity_curve: EquityPoint[];
  predictions: PredictionPoint[];
  signals: TradeSignal[];
  strategy_breakdown: StrategyPerformance[];
  candles: OHLCVCandle[];
}

export interface BacktestRequest {
  symbol: string;
  timeframe: string;
  start_date: string;
  end_date: string;
  initial_capital: number;
  strategies: string[];
  position_size_percent: number;
  max_positions: number;
  stop_loss_percent?: number;
  take_profit_percent?: number;
  use_trailing_stop?: boolean;
  include_predictions?: boolean;
}

export interface ModelAccuracy {
  model: string;
  total_predictions: number;
  correct_direction: number;
  direction_accuracy: number;
  mae_high: number;
  mae_low: number;
  rmse_high: number;
  rmse_low: number;
  avg_confidence: number;
  confidence_calibration: number;
}

// ============================================================================
// API Functions
// ============================================================================

/**
 * Get historical OHLCV candles via Data Service proxy
 */
export async function getHistoricalCandles(
  symbol: string,
  timeframe: string,
  startDate: string,
  endDate: string,
  limit: number = 1000
): Promise<CandlesResponse | null> {
  try {
    const response = await apiClient.get(`/proxy/data/candles/${symbol}`, {
      params: {
        timeframe,
        start: startDate,
        end: endDate,
        limit: limit.toString(),
      },
    });
    return response.data;
  } catch (error) {
    console.error('Error fetching historical candles:', error);
    return null;
  }
}

/**
 * Run backtest with predictions via ML proxy
 */
export async function runBacktest(request: BacktestRequest): Promise<BacktestResult | null> {
  try {
    const response = await apiClient.post('/proxy/ml/backtest/run', {
      symbol: request.symbol,
      strategy: request.strategies[0] || 'ensemble',
      startDate: request.start_date,
      endDate: request.end_date,
    });
    return response.data;
  } catch (error) {
    console.error('Error running backtest:', error);
    return null;
  }
}

/**
 * Get historical predictions for a symbol via ML proxy
 */
export async function getHistoricalPredictions(
  symbol: string,
  _timeframe: string,
  startDate: string,
  endDate: string
): Promise<PredictionPoint[]> {
  try {
    const response = await apiClient.get(`/proxy/ml/predictions/history/${symbol}`, {
      params: {
        startDate,
        endDate,
      },
    });
    return response.data?.predictions || response.data || [];
  } catch (error) {
    console.error('Error fetching historical predictions:', error);
    return [];
  }
}

/**
 * Get historical signals for a symbol (uses Express ML routes)
 */
export async function getHistoricalSignals(
  symbol: string,
  startDate: string,
  endDate: string
): Promise<TradeSignal[]> {
  try {
    const response = await apiClient.get(`/ml/signals/history/${symbol}`, {
      params: {
        start_date: startDate,
        end_date: endDate,
      },
    });
    return response.data?.signals || response.data || [];
  } catch (error) {
    console.error('Error fetching historical signals:', error);
    return [];
  }
}

/**
 * Get model accuracy metrics via ML proxy
 */
export async function getModelAccuracy(
  symbol: string,
  _timeframe: string,
  _startDate: string,
  _endDate: string
): Promise<ModelAccuracy[]> {
  try {
    const response = await apiClient.get(`/proxy/ml/models/accuracy/${symbol}`);
    return response.data?.models || response.data || [];
  } catch (error) {
    console.error('Error fetching model accuracy:', error);
    return [];
  }
}

/**
 * Get available date range for a symbol via Data Service proxy
 */
export async function getAvailableDateRange(symbol: string): Promise<{
  start_date: string;
  end_date: string;
  total_candles: number;
} | null> {
  try {
    const response = await apiClient.get(`/proxy/data/symbols/${symbol}/date-range`);
    return response.data;
  } catch (error) {
    console.error('Error fetching date range:', error);
    return null;
  }
}

/**
 * Get available strategies via ML proxy
 */
export async function getAvailableStrategies(): Promise<{
  id: string;
  name: string;
  description: string;
  type: string;
}[]> {
  try {
    const response = await apiClient.get('/proxy/ml/strategies');
    return response.data?.strategies || response.data || getDefaultStrategies();
  } catch (error) {
    console.error('Error fetching strategies:', error);
    return getDefaultStrategies();
  }
}

function getDefaultStrategies() {
  return [
    { id: 'range_predictor', name: 'Range Predictor', description: 'Predice ΔHigh/ΔLow usando XGBoost', type: 'ml' },
    { id: 'amd_detector', name: 'AMD Detector', description: 'Detecta fases Accumulation-Manipulation-Distribution', type: 'pattern' },
    { id: 'ict_smc', name: 'ICT/SMC', description: 'Smart Money Concepts - Order Blocks, FVG', type: 'pattern' },
    { id: 'tp_sl_classifier', name: 'TP/SL Classifier', description: 'Clasifica probabilidad de alcanzar TP primero', type: 'ml' },
    { id: 'ensemble', name: 'Ensemble', description: 'Combinación ponderada de todas las estrategias', type: 'ensemble' },
  ];
}

/**
 * Compare strategies performance via ML proxy
 */
export async function compareStrategies(
  symbol: string,
  _timeframe: string,
  startDate: string,
  endDate: string,
  strategies: string[]
): Promise<StrategyPerformance[]> {
  try {
    const response = await apiClient.post('/proxy/ml/backtest/compare', {
      symbol,
      strategies,
      startDate,
      endDate,
    });
    return response.data?.results || response.data || [];
  } catch (error) {
    console.error('Error comparing strategies:', error);
    return [];
  }
}

// ============================================================================
// Utility Functions
// ============================================================================

/**
 * Calculate prediction accuracy from historical data
 */
export function calculatePredictionAccuracy(predictions: PredictionPoint[]): {
  direction_accuracy: number;
  high_mae: number;
  low_mae: number;
  avg_confidence: number;
} {
  if (predictions.length === 0) {
    return { direction_accuracy: 0, high_mae: 0, low_mae: 0, avg_confidence: 0 };
  }

  let correctDirection = 0;
  let totalHighError = 0;
  let totalLowError = 0;
  let totalConfidence = 0;

  predictions.forEach((p) => {
    // Check if predicted direction matches actual movement
    const predictedUp = p.delta_high_predicted > Math.abs(p.delta_low_predicted);
    const actualUp = p.delta_high_actual > Math.abs(p.delta_low_actual);
    if (predictedUp === actualUp) correctDirection++;

    // Calculate absolute errors
    totalHighError += Math.abs(p.delta_high_predicted - p.delta_high_actual);
    totalLowError += Math.abs(p.delta_low_predicted - p.delta_low_actual);
    totalConfidence += (p.confidence_high + p.confidence_low) / 2;
  });

  return {
    direction_accuracy: (correctDirection / predictions.length) * 100,
    high_mae: totalHighError / predictions.length,
    low_mae: totalLowError / predictions.length,
    avg_confidence: (totalConfidence / predictions.length) * 100,
  };
}

/**
 * Format metrics for display
 */
export function formatMetric(value: number, type: 'percent' | 'currency' | 'ratio' | 'number'): string {
  switch (type) {
    case 'percent':
      return `${value >= 0 ? '+' : ''}${value.toFixed(2)}%`;
    case 'currency':
      return `$${value.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
    case 'ratio':
      return value.toFixed(2);
    case 'number':
      return value.toLocaleString();
    default:
      return value.toString();
  }
}

/**
 * Get color for metric value
 */
export function getMetricColor(value: number, type: 'pnl' | 'winrate' | 'drawdown' | 'ratio'): string {
  switch (type) {
    case 'pnl':
      return value >= 0 ? 'text-green-400' : 'text-red-400';
    case 'winrate':
      return value >= 60 ? 'text-green-400' : value >= 50 ? 'text-yellow-400' : 'text-red-400';
    case 'drawdown':
      return value <= 10 ? 'text-green-400' : value <= 20 ? 'text-yellow-400' : 'text-red-400';
    case 'ratio':
      return value >= 1.5 ? 'text-green-400' : value >= 1 ? 'text-yellow-400' : 'text-red-400';
    default:
      return 'text-white';
  }
}

export default {
  getHistoricalCandles,
  runBacktest,
  getHistoricalPredictions,
  getHistoricalSignals,
  getModelAccuracy,
  getAvailableDateRange,
  getAvailableStrategies,
  compareStrategies,
  calculatePredictionAccuracy,
  formatMetric,
  getMetricColor,
};
