/**
 * CandlestickChartWithML Component
 * Lightweight Charts with ML prediction overlays
 * Displays: Order Blocks, Fair Value Gaps, Range Predictions, Signal Markers
 */

import { useEffect, useRef, useCallback, useState } from 'react';
import {
  createChart,
  IChartApi,
  ISeriesApi,
  CandlestickData,
  HistogramData,
  Time,
  ColorType,
  CrosshairMode,
  LineStyle,
  PriceLineOptions,
  SeriesMarker,
} from 'lightweight-charts';
import type { Candle, CandlestickChartProps } from '../../../types/trading.types';
import type { MLSignal, RangePrediction, AMDPhase, AMDZone } from '../../../services/mlService';
import { getLatestSignal, getRangePrediction, getAMDPhase, getAMDZones } from '../../../services/mlService';

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

interface OrderBlock {
  id: string;
  type: 'bullish' | 'bearish';
  priceHigh: number;
  priceLow: number;
  timeStart: number;
  timeEnd?: number;
  strength: number;
  tested: boolean;
}

interface FairValueGap {
  id: string;
  type: 'bullish' | 'bearish';
  priceHigh: number;
  priceLow: number;
  time: number;
  filled: boolean;
  fillPercentage: number;
}

interface MLOverlays {
  signal?: MLSignal | null;
  rangePrediction?: RangePrediction | null;
  amdPhase?: AMDPhase | null;
  amdZones?: AMDZone[];
  orderBlocks?: OrderBlock[];
  fairValueGaps?: FairValueGap[];
}

interface CandlestickChartWithMLProps extends CandlestickChartProps {
  enableMLOverlays?: boolean;
  showSignalLevels?: boolean;
  showRangePrediction?: boolean;
  showOrderBlocks?: boolean;
  showFairValueGaps?: boolean;
  showAMDPhase?: boolean;
  showAMDZones?: boolean;
  autoRefreshML?: boolean;
  refreshInterval?: number;
}

// ============================================================================
// Theme Configuration
// ============================================================================

interface ChartTheme {
  backgroundColor: string;
  textColor: string;
  gridColor: string;
  upColor: string;
  downColor: string;
  borderUpColor: string;
  borderDownColor: string;
  wickUpColor: string;
  wickDownColor: string;
  volumeUpColor: string;
  volumeDownColor: string;
}

const THEMES: Record<'dark' | 'light', ChartTheme> = {
  dark: {
    backgroundColor: '#1a1a2e',
    textColor: '#d1d4dc',
    gridColor: '#2B2B43',
    upColor: '#10b981',
    downColor: '#ef4444',
    borderUpColor: '#10b981',
    borderDownColor: '#ef4444',
    wickUpColor: '#10b981',
    wickDownColor: '#ef4444',
    volumeUpColor: 'rgba(16, 185, 129, 0.5)',
    volumeDownColor: 'rgba(239, 68, 68, 0.5)',
  },
  light: {
    backgroundColor: '#ffffff',
    textColor: '#131722',
    gridColor: '#e1e1e1',
    upColor: '#10b981',
    downColor: '#ef4444',
    borderUpColor: '#10b981',
    borderDownColor: '#ef4444',
    wickUpColor: '#10b981',
    wickDownColor: '#ef4444',
    volumeUpColor: 'rgba(16, 185, 129, 0.5)',
    volumeDownColor: 'rgba(239, 68, 68, 0.5)',
  },
};

// ML Overlay Colors
const ML_COLORS = {
  entryLine: '#3b82f6',
  stopLoss: '#ef4444',
  takeProfit: '#10b981',
  rangePredictionHigh: 'rgba(16, 185, 129, 0.3)',
  rangePredictionLow: 'rgba(239, 68, 68, 0.3)',
  orderBlockBullish: 'rgba(16, 185, 129, 0.15)',
  orderBlockBearish: 'rgba(239, 68, 68, 0.15)',
  fvgBullish: 'rgba(59, 130, 246, 0.2)',
  fvgBearish: 'rgba(249, 115, 22, 0.2)',
  amdAccumulation: 'rgba(59, 130, 246, 0.1)',
  amdManipulation: 'rgba(249, 115, 22, 0.1)',
  amdDistribution: 'rgba(139, 92, 246, 0.1)',
};

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

export const CandlestickChartWithML: React.FC<CandlestickChartWithMLProps> = ({
  symbol,
  interval = '1h',
  height = 500,
  theme = 'dark',
  showVolume = true,
  onCrosshairMove,
  enableMLOverlays = true,
  showSignalLevels = true,
  showRangePrediction = true,
  showOrderBlocks = false,
  showFairValueGaps = false,
  showAMDPhase = true,
  showAMDZones = true,
  autoRefreshML = true,
  refreshInterval = 30000,
}) => {
  const containerRef = useRef<HTMLDivElement>(null);
  const chartRef = useRef<IChartApi | null>(null);
  const candleSeriesRef = useRef<ISeriesApi<'Candlestick'> | null>(null);
  const volumeSeriesRef = useRef<ISeriesApi<'Histogram'> | null>(null);
  const rangeHighSeriesRef = useRef<ISeriesApi<'Line'> | null>(null);
  const rangeLowSeriesRef = useRef<ISeriesApi<'Line'> | null>(null);
  const resizeObserverRef = useRef<ResizeObserver | null>(null);
  const priceLinesRef = useRef<ReturnType<ISeriesApi<'Candlestick'>['createPriceLine']>[]>([]);
  const amdZoneSeriesRef = useRef<Map<string, ISeriesApi<'Area'>>>(new Map());

  const [mlOverlays, setMlOverlays] = useState<MLOverlays>({});
  const [isLoadingML, setIsLoadingML] = useState(false);

  const chartTheme = THEMES[theme];

  // Fetch ML data
  const fetchMLData = useCallback(async () => {
    if (!enableMLOverlays || !symbol) return;

    setIsLoadingML(true);
    try {
      const [signal, rangePred, amd, zones] = await Promise.all([
        showSignalLevels ? getLatestSignal(symbol) : Promise.resolve(null),
        showRangePrediction ? getRangePrediction(symbol, interval) : Promise.resolve(null),
        showAMDPhase ? getAMDPhase(symbol) : Promise.resolve(null),
        showAMDZones ? getAMDZones(symbol, interval, 10) : Promise.resolve([]),
      ]);

      setMlOverlays({
        signal,
        rangePrediction: rangePred,
        amdPhase: amd,
        amdZones: zones,
      });
    } catch (error) {
      console.error('Error fetching ML data:', error);
    } finally {
      setIsLoadingML(false);
    }
  }, [symbol, interval, enableMLOverlays, showSignalLevels, showRangePrediction, showAMDPhase, showAMDZones]);

  // Auto-refresh ML data
  useEffect(() => {
    if (enableMLOverlays && autoRefreshML) {
      fetchMLData();
      const intervalId = setInterval(fetchMLData, refreshInterval);
      return () => clearInterval(intervalId);
    }
  }, [fetchMLData, autoRefreshML, refreshInterval, enableMLOverlays]);

  // Initialize chart
  useEffect(() => {
    if (!containerRef.current) return;

    const chart = createChart(containerRef.current, {
      width: containerRef.current.clientWidth,
      height,
      layout: {
        background: { type: ColorType.Solid, color: chartTheme.backgroundColor },
        textColor: chartTheme.textColor,
      },
      grid: {
        vertLines: { color: chartTheme.gridColor },
        horzLines: { color: chartTheme.gridColor },
      },
      crosshair: {
        mode: CrosshairMode.Normal,
        vertLine: {
          width: 1,
          color: 'rgba(224, 227, 235, 0.4)',
          style: LineStyle.Solid,
          labelBackgroundColor: chartTheme.backgroundColor,
        },
        horzLine: {
          width: 1,
          color: 'rgba(224, 227, 235, 0.4)',
          style: LineStyle.Solid,
          labelBackgroundColor: chartTheme.backgroundColor,
        },
      },
      rightPriceScale: {
        borderColor: chartTheme.gridColor,
      },
      timeScale: {
        borderColor: chartTheme.gridColor,
        timeVisible: true,
        secondsVisible: false,
      },
    });

    // Add candlestick series
    const candleSeries = chart.addCandlestickSeries({
      upColor: chartTheme.upColor,
      downColor: chartTheme.downColor,
      borderUpColor: chartTheme.borderUpColor,
      borderDownColor: chartTheme.borderDownColor,
      wickUpColor: chartTheme.wickUpColor,
      wickDownColor: chartTheme.wickDownColor,
    });

    // Add volume series
    let volumeSeries: ISeriesApi<'Histogram'> | null = null;
    if (showVolume) {
      volumeSeries = chart.addHistogramSeries({
        color: chartTheme.volumeUpColor,
        priceFormat: { type: 'volume' },
        priceScaleId: '',
      });
      volumeSeries.priceScale().applyOptions({
        scaleMargins: { top: 0.8, bottom: 0 },
      });
    }

    // Add range prediction lines (invisible initially)
    const rangeHighSeries = chart.addLineSeries({
      color: ML_COLORS.rangePredictionHigh,
      lineWidth: 1,
      lineStyle: LineStyle.Dashed,
      priceLineVisible: false,
      lastValueVisible: false,
      crosshairMarkerVisible: false,
    });

    const rangeLowSeries = chart.addLineSeries({
      color: ML_COLORS.rangePredictionLow,
      lineWidth: 1,
      lineStyle: LineStyle.Dashed,
      priceLineVisible: false,
      lastValueVisible: false,
      crosshairMarkerVisible: false,
    });

    // Handle crosshair movement
    chart.subscribeCrosshairMove((param) => {
      if (!param || !param.time || !param.seriesData) {
        onCrosshairMove?.(null);
        return;
      }

      const candleData = param.seriesData.get(candleSeries) as CandlestickData;
      if (candleData) {
        onCrosshairMove?.({
          time: param.time,
          price: candleData.close as number,
        });
      }
    });

    chartRef.current = chart;
    candleSeriesRef.current = candleSeries;
    volumeSeriesRef.current = volumeSeries;
    rangeHighSeriesRef.current = rangeHighSeries;
    rangeLowSeriesRef.current = rangeLowSeries;

    // Setup ResizeObserver
    const resizeObserver = new ResizeObserver((entries) => {
      if (entries[0] && chartRef.current) {
        const { width } = entries[0].contentRect;
        chartRef.current.applyOptions({ width });
      }
    });

    resizeObserver.observe(containerRef.current);
    resizeObserverRef.current = resizeObserver;

    return () => {
      resizeObserver.disconnect();
      chart.remove();
    };
  }, [height, showVolume, chartTheme, onCrosshairMove]);

  // Update price lines when ML signal changes
  useEffect(() => {
    if (!candleSeriesRef.current || !showSignalLevels) return;

    // Remove old price lines
    priceLinesRef.current.forEach((line) => {
      candleSeriesRef.current?.removePriceLine(line);
    });
    priceLinesRef.current = [];

    // Add new price lines for signal
    if (mlOverlays.signal) {
      const signal = mlOverlays.signal;

      // Entry line
      const entryLine = candleSeriesRef.current.createPriceLine({
        price: signal.entry_price,
        color: ML_COLORS.entryLine,
        lineWidth: 2,
        lineStyle: LineStyle.Solid,
        axisLabelVisible: true,
        title: `Entry ${signal.direction.toUpperCase()}`,
      } as PriceLineOptions);
      priceLinesRef.current.push(entryLine);

      // Stop Loss line
      const slLine = candleSeriesRef.current.createPriceLine({
        price: signal.stop_loss,
        color: ML_COLORS.stopLoss,
        lineWidth: 1,
        lineStyle: LineStyle.Dashed,
        axisLabelVisible: true,
        title: 'SL',
      } as PriceLineOptions);
      priceLinesRef.current.push(slLine);

      // Take Profit line
      const tpLine = candleSeriesRef.current.createPriceLine({
        price: signal.take_profit,
        color: ML_COLORS.takeProfit,
        lineWidth: 1,
        lineStyle: LineStyle.Dashed,
        axisLabelVisible: true,
        title: 'TP',
      } as PriceLineOptions);
      priceLinesRef.current.push(tpLine);
    }

    // Add range prediction lines
    if (mlOverlays.rangePrediction && rangeHighSeriesRef.current && rangeLowSeriesRef.current) {
      const pred = mlOverlays.rangePrediction;

      // Support/Resistance from AMD
      if (mlOverlays.amdPhase?.key_levels) {
        const supportLine = candleSeriesRef.current.createPriceLine({
          price: mlOverlays.amdPhase.key_levels.support,
          color: 'rgba(59, 130, 246, 0.5)',
          lineWidth: 1,
          lineStyle: LineStyle.Dotted,
          axisLabelVisible: true,
          title: 'Support',
        } as PriceLineOptions);
        priceLinesRef.current.push(supportLine);

        const resistanceLine = candleSeriesRef.current.createPriceLine({
          price: mlOverlays.amdPhase.key_levels.resistance,
          color: 'rgba(249, 115, 22, 0.5)',
          lineWidth: 1,
          lineStyle: LineStyle.Dotted,
          axisLabelVisible: true,
          title: 'Resistance',
        } as PriceLineOptions);
        priceLinesRef.current.push(resistanceLine);
      }

      // Predicted range lines
      const predHighLine = candleSeriesRef.current.createPriceLine({
        price: pred.predicted_high,
        color: ML_COLORS.rangePredictionHigh.replace('0.3', '0.7'),
        lineWidth: 1,
        lineStyle: LineStyle.LargeDashed,
        axisLabelVisible: true,
        title: `Pred High (${(pred.prediction_confidence * 100).toFixed(0)}%)`,
      } as PriceLineOptions);
      priceLinesRef.current.push(predHighLine);

      const predLowLine = candleSeriesRef.current.createPriceLine({
        price: pred.predicted_low,
        color: ML_COLORS.rangePredictionLow.replace('0.3', '0.7'),
        lineWidth: 1,
        lineStyle: LineStyle.LargeDashed,
        axisLabelVisible: true,
        title: `Pred Low`,
      } as PriceLineOptions);
      priceLinesRef.current.push(predLowLine);
    }
  }, [mlOverlays, showSignalLevels, showRangePrediction]);

  // Update AMD zones visualization
  useEffect(() => {
    if (!chartRef.current || !showAMDZones) return;

    const chart = chartRef.current;

    // Clear existing AMD zone series
    amdZoneSeriesRef.current.forEach((series) => {
      try {
        chart.removeSeries(series);
      } catch {
        // Series might already be removed
      }
    });
    amdZoneSeriesRef.current.clear();

    // Render new AMD zones
    const zones = mlOverlays.amdZones || [];
    if (zones.length === 0) return;

    zones.forEach((zone, index) => {
      const zoneId = `amd-zone-${index}-${zone.phase}`;

      // Get color based on phase
      let zoneColor: string;
      switch (zone.phase) {
        case 'accumulation':
          zoneColor = ML_COLORS.amdAccumulation;
          break;
        case 'manipulation':
          zoneColor = ML_COLORS.amdManipulation;
          break;
        case 'distribution':
          zoneColor = ML_COLORS.amdDistribution;
          break;
        default:
          zoneColor = 'rgba(107, 114, 128, 0.1)';
      }

      // Adjust opacity based on confidence
      const opacity = Math.max(0.05, 0.15 * zone.confidence);
      const adjustedColor = zoneColor.replace(/[\d.]+\)$/, `${opacity})`);

      // Create area series for zone
      const areaSeries = chart.addAreaSeries({
        topColor: adjustedColor,
        bottomColor: 'transparent',
        lineColor: 'transparent',
        lineWidth: 1,
        crosshairMarkerVisible: false,
        lastValueVisible: false,
        priceLineVisible: false,
      });

      // Set zone data
      const startTime = (zone.startTime / 1000) as Time;
      const endTime = (zone.endTime / 1000) as Time;

      areaSeries.setData([
        { time: startTime, value: zone.priceHigh },
        { time: endTime, value: zone.priceHigh },
      ]);

      amdZoneSeriesRef.current.set(zoneId, areaSeries);
    });

    return () => {
      amdZoneSeriesRef.current.forEach((series) => {
        try {
          chart.removeSeries(series);
        } catch {
          // Series might already be removed
        }
      });
      amdZoneSeriesRef.current.clear();
    };
  }, [mlOverlays.amdZones, showAMDZones]);

  // Update data method
  const updateData = useCallback(
    (candles: Candle[]) => {
      if (!candleSeriesRef.current || candles.length === 0) return;

      // Transform data for candlestick series
      const candleData: CandlestickData[] = candles.map((c) => ({
        time: (c.time / 1000) as Time,
        open: c.open,
        high: c.high,
        low: c.low,
        close: c.close,
      }));

      candleSeriesRef.current.setData(candleData);

      // Add signal markers
      if (mlOverlays.signal) {
        const signal = mlOverlays.signal;
        const signalTime = new Date(signal.created_at).getTime() / 1000;

        // Find the candle closest to signal time
        const closestCandle = candleData.reduce((prev, curr) => {
          return Math.abs((curr.time as number) - signalTime) < Math.abs((prev.time as number) - signalTime) ? curr : prev;
        });

        const markers: SeriesMarker<Time>[] = [{
          time: closestCandle.time,
          position: signal.direction === 'long' ? 'belowBar' : 'aboveBar',
          color: signal.direction === 'long' ? ML_COLORS.takeProfit : ML_COLORS.stopLoss,
          shape: signal.direction === 'long' ? 'arrowUp' : 'arrowDown',
          text: `${signal.direction.toUpperCase()} ${(signal.confidence_score * 100).toFixed(0)}%`,
        }];

        candleSeriesRef.current.setMarkers(markers);
      }

      // Transform data for volume series
      if (volumeSeriesRef.current && showVolume) {
        const volumeData: HistogramData[] = candles.map((c) => ({
          time: (c.time / 1000) as Time,
          value: c.volume,
          color: c.close >= c.open ? chartTheme.volumeUpColor : chartTheme.volumeDownColor,
        }));
        volumeSeriesRef.current.setData(volumeData);
      }

      // Fit content
      chartRef.current?.timeScale().fitContent();
    },
    [showVolume, chartTheme, mlOverlays.signal]
  );

  // Expose updateData method through ref
  useEffect(() => {
    if (containerRef.current) {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      (containerRef.current as any).updateData = updateData;
    }
  }, [updateData]);

  return (
    <div className="relative w-full" style={{ height }}>
      {/* ML Status Indicator */}
      {enableMLOverlays && (
        <div className="absolute top-2 right-2 z-10 flex items-center gap-2">
          {isLoadingML && (
            <div className="flex items-center gap-1 px-2 py-1 bg-gray-800/80 rounded text-xs text-gray-400">
              <svg className="animate-spin h-3 w-3" viewBox="0 0 24 24">
                <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none" />
                <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
              </svg>
              <span>ML</span>
            </div>
          )}

          {mlOverlays.amdPhase && (
            <div className={`px-2 py-1 rounded text-xs font-medium ${
              mlOverlays.amdPhase.phase === 'accumulation' ? 'bg-blue-500/20 text-blue-400' :
              mlOverlays.amdPhase.phase === 'manipulation' ? 'bg-orange-500/20 text-orange-400' :
              mlOverlays.amdPhase.phase === 'distribution' ? 'bg-purple-500/20 text-purple-400' :
              'bg-gray-500/20 text-gray-400'
            }`}>
              {mlOverlays.amdPhase.phase.toUpperCase()} {(mlOverlays.amdPhase.confidence * 100).toFixed(0)}%
            </div>
          )}

          {mlOverlays.rangePrediction && (
            <div className="px-2 py-1 bg-gray-800/80 rounded text-xs text-gray-300">
              Range: {mlOverlays.rangePrediction.expected_range_percent.toFixed(2)}%
            </div>
          )}

          {mlOverlays.signal && (
            <div className={`px-2 py-1 rounded text-xs font-medium ${
              mlOverlays.signal.direction === 'long' ? 'bg-green-500/20 text-green-400' : 'bg-red-500/20 text-red-400'
            }`}>
              {mlOverlays.signal.direction.toUpperCase()} • RR {mlOverlays.signal.risk_reward_ratio.toFixed(1)}
            </div>
          )}
        </div>
      )}

      {/* Signal Details Panel */}
      {enableMLOverlays && mlOverlays.signal && (
        <div className="absolute bottom-2 left-2 z-10 bg-gray-900/90 backdrop-blur-sm rounded-lg p-3 border border-gray-700 text-xs max-w-xs">
          <div className="flex items-center gap-2 mb-2">
            <span className={`px-2 py-0.5 rounded font-bold ${
              mlOverlays.signal.direction === 'long' ? 'bg-green-500 text-white' : 'bg-red-500 text-white'
            }`}>
              {mlOverlays.signal.direction.toUpperCase()}
            </span>
            <span className="text-gray-400">
              {(mlOverlays.signal.confidence_score * 100).toFixed(0)}% confidence
            </span>
          </div>
          <div className="grid grid-cols-3 gap-2 text-gray-300">
            <div>
              <span className="text-gray-500 block">Entry</span>
              <span className="text-blue-400 font-mono">{mlOverlays.signal.entry_price.toFixed(5)}</span>
            </div>
            <div>
              <span className="text-gray-500 block">SL</span>
              <span className="text-red-400 font-mono">{mlOverlays.signal.stop_loss.toFixed(5)}</span>
            </div>
            <div>
              <span className="text-gray-500 block">TP</span>
              <span className="text-green-400 font-mono">{mlOverlays.signal.take_profit.toFixed(5)}</span>
            </div>
          </div>
          <div className="mt-2 pt-2 border-t border-gray-700 flex justify-between text-gray-400">
            <span>P(TP First): {(mlOverlays.signal.prob_tp_first * 100).toFixed(0)}%</span>
            <span>RR: {mlOverlays.signal.risk_reward_ratio.toFixed(2)}</span>
          </div>
        </div>
      )}

      {/* Chart Container */}
      <div
        ref={containerRef}
        className="w-full h-full"
        data-symbol={symbol}
        data-interval={interval}
      />
    </div>
  );
};

export default CandlestickChartWithML;
