/**
 * MLPredictionOverlay Component
 * Renders ML price predictions with confidence bands on the trading chart
 * Supports: prediction line, upper/lower confidence bands, bullish/bearish colors
 */

import { useEffect, useRef } from 'react';
import type { IChartApi, ISeriesApi, LineData, Time } from 'lightweight-charts';
import type { MLPrediction } from '../../../../../types/mlOverlay.types';

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

export interface MLPredictionOverlayProps {
  chartRef: React.RefObject<IChartApi>;
  predictions: MLPrediction[];
  visible?: boolean;
  showConfidenceBands?: boolean;
  colors?: {
    bullish: string;
    bearish: string;
    neutral: string;
    bandUpper: string;
    bandLower: string;
  };
  lineWidth?: number;
  bandOpacity?: number;
}

// ============================================================================
// Default Colors
// ============================================================================

const DEFAULT_COLORS = {
  bullish: '#10b981',
  bearish: '#ef4444',
  neutral: '#3b82f6',
  bandUpper: 'rgba(16, 185, 129, 0.15)',
  bandLower: 'rgba(239, 68, 68, 0.15)',
};

// ============================================================================
// Helper Functions
// ============================================================================

function getPredictionColor(type: MLPrediction['type'], colors: typeof DEFAULT_COLORS): string {
  switch (type) {
    case 'buy':
      return colors.bullish;
    case 'sell':
      return colors.bearish;
    default:
      return colors.neutral;
  }
}

function calculateConfidenceBand(price: number, confidence: number, direction: 'upper' | 'lower'): number {
  const bandWidth = price * (1 - confidence) * 0.02;
  return direction === 'upper' ? price + bandWidth : price - bandWidth;
}

// ============================================================================
// Component
// ============================================================================

export const MLPredictionOverlay: React.FC<MLPredictionOverlayProps> = ({
  chartRef,
  predictions,
  visible = true,
  showConfidenceBands = true,
  colors = DEFAULT_COLORS,
  lineWidth = 2,
  bandOpacity = 0.15,
}) => {
  const predictionSeriesRef = useRef<ISeriesApi<'Line'> | null>(null);
  const upperBandSeriesRef = useRef<ISeriesApi<'Line'> | null>(null);
  const lowerBandSeriesRef = useRef<ISeriesApi<'Line'> | null>(null);
  const areaSeriesRef = useRef<ISeriesApi<'Area'> | null>(null);

  // Initialize prediction series
  useEffect(() => {
    if (!chartRef.current || !visible) return;

    const chart = chartRef.current;

    // Create main prediction line series
    const predictionSeries = chart.addLineSeries({
      color: colors.neutral,
      lineWidth: lineWidth as 1 | 2 | 3 | 4,
      lineStyle: 0,
      crosshairMarkerVisible: true,
      crosshairMarkerRadius: 4,
      lastValueVisible: true,
      priceLineVisible: false,
      title: 'ML Prediction',
    });
    predictionSeriesRef.current = predictionSeries;

    // Create confidence band series if enabled
    if (showConfidenceBands) {
      // Upper band (dashed line)
      const upperBandSeries = chart.addLineSeries({
        color: colors.bandUpper.replace(String(bandOpacity), '0.5'),
        lineWidth: 1,
        lineStyle: 2,
        crosshairMarkerVisible: false,
        lastValueVisible: false,
        priceLineVisible: false,
      });
      upperBandSeriesRef.current = upperBandSeries;

      // Lower band (dashed line)
      const lowerBandSeries = chart.addLineSeries({
        color: colors.bandLower.replace(String(bandOpacity), '0.5'),
        lineWidth: 1,
        lineStyle: 2,
        crosshairMarkerVisible: false,
        lastValueVisible: false,
        priceLineVisible: false,
      });
      lowerBandSeriesRef.current = lowerBandSeries;

      // Area fill between bands
      const areaSeries = chart.addAreaSeries({
        topColor: `rgba(59, 130, 246, ${bandOpacity})`,
        bottomColor: 'transparent',
        lineColor: 'transparent',
        crosshairMarkerVisible: false,
        lastValueVisible: false,
        priceLineVisible: false,
      });
      areaSeriesRef.current = areaSeries;
    }

    return () => {
      if (predictionSeriesRef.current) {
        try { chart.removeSeries(predictionSeriesRef.current); } catch { /* ignore */ }
        predictionSeriesRef.current = null;
      }
      if (upperBandSeriesRef.current) {
        try { chart.removeSeries(upperBandSeriesRef.current); } catch { /* ignore */ }
        upperBandSeriesRef.current = null;
      }
      if (lowerBandSeriesRef.current) {
        try { chart.removeSeries(lowerBandSeriesRef.current); } catch { /* ignore */ }
        lowerBandSeriesRef.current = null;
      }
      if (areaSeriesRef.current) {
        try { chart.removeSeries(areaSeriesRef.current); } catch { /* ignore */ }
        areaSeriesRef.current = null;
      }
    };
  }, [chartRef, visible, showConfidenceBands, colors, lineWidth, bandOpacity]);

  // Update prediction data
  useEffect(() => {
    if (!predictionSeriesRef.current || !visible || predictions.length === 0) {
      return;
    }

    // Sort predictions by time
    const sortedPredictions = [...predictions].sort((a, b) => a.timestamp - b.timestamp);

    // Main prediction line
    const lineData: LineData[] = sortedPredictions.map((pred) => ({
      time: (pred.timestamp / 1000) as Time,
      value: pred.price,
    }));
    predictionSeriesRef.current.setData(lineData);

    // Update line color based on latest prediction type
    const latestPrediction = sortedPredictions[sortedPredictions.length - 1];
    const lineColor = getPredictionColor(latestPrediction.type, colors);
    predictionSeriesRef.current.applyOptions({ color: lineColor });

    // Update confidence bands if enabled
    if (showConfidenceBands && upperBandSeriesRef.current && lowerBandSeriesRef.current) {
      const upperBandData: LineData[] = sortedPredictions.map((pred) => ({
        time: (pred.timestamp / 1000) as Time,
        value: calculateConfidenceBand(pred.price, pred.confidence, 'upper'),
      }));

      const lowerBandData: LineData[] = sortedPredictions.map((pred) => ({
        time: (pred.timestamp / 1000) as Time,
        value: calculateConfidenceBand(pred.price, pred.confidence, 'lower'),
      }));

      upperBandSeriesRef.current.setData(upperBandData);
      lowerBandSeriesRef.current.setData(lowerBandData);

      // Update area series with upper band data
      if (areaSeriesRef.current) {
        areaSeriesRef.current.setData(upperBandData);
      }
    }
  }, [predictions, visible, showConfidenceBands, colors]);

  // Update visibility
  useEffect(() => {
    const series = [
      predictionSeriesRef.current,
      upperBandSeriesRef.current,
      lowerBandSeriesRef.current,
      areaSeriesRef.current,
    ];

    series.forEach((s) => {
      if (s) {
        s.applyOptions({ visible });
      }
    });
  }, [visible]);

  return null;
};

export default MLPredictionOverlay;
