'use client';

import { useEffect, useRef, useState, useImperativeHandle, forwardRef } from 'react';
import { createChart, IChartApi, ISeriesApi, CandlestickData, HistogramData, Time, SeriesMarker } from 'lightweight-charts';
import { useTheme } from 'next-themes';
import SvgOverlay from './SvgOverlay';
import SpanAnnotationManager from './SpanAnnotationManager';
import { TrendLine } from '@/plugins/trend-line';
import { RectangleDrawingPrimitive, RectanglePoint } from '@/plugins/rectangle-drawing';
import type { PerCandlePrediction, PredictionSpan, ModelInfoResponse, PredictionSummary } from '@/types/predictions';

interface DrawingState {
  tool: 'line' | 'rectangle';
  firstPoint: { time: Time; price: number };
}

interface Point {
  time: Time;
  price: number;
}

interface Candle {
  time: number;
  open: number;
  high: number;
  low: number;
  close: number;
}

interface Annotation {
  id: number;
  timestamp: number;
  label_type: string;
  geometry: {
    startTime?: number;
    startPrice?: number;
    endTime?: number;
    endPrice?: number;
  } | null;
  created_at: number;
}

type AnnotationType = {
  id: number;
  name: string;
  display_name: string;
  color: string;
  category: string;
  icon: string | null;
  is_active: number;
};

interface SpanAnnotation {
  id: number;
  chart_id: number;
  start_time: number;
  end_time: number;
  label: string;
  confidence: number | null;
  outcome: string | null;
  notes: string | null;
  sub_spans: any;
  color: string;
  created_at: number;
}

interface SpanLabelType {
  id: number;
  name: string;
  display_name: string;
  color: string;
  hotkey: string | null;
  is_active: number;
  sort_order: number;
  created_at: number;
}

interface CandleChartProps {
  activeTool: string | null;
  onAnnotationChange?: () => void;
  selectedColor: string;
  selectedLabelId?: number | null;
  onLabelSelect?: (id: number) => void;
  activeChartId?: number | null;
  spanAnnotations?: SpanAnnotation[];
  spanLabelTypes?: SpanLabelType[];
  selectedSpanId?: number | null;
  onSpanAnnotationsChange?: () => void;
  onSelectedSpanChange?: (spanId: number | null) => void;
  // Prediction rendering props
  predictionVisible?: boolean;
  perCandlePredictions?: PerCandlePrediction[];
  predictionSpans?: PredictionSpan[];
  confidenceThreshold?: number;
  selectedLabels?: Set<string>;
  modelInfo?: ModelInfoResponse | null;
  predictionSummary?: PredictionSummary | null;
  showOnlyDisagreements?: boolean;
  onPredictionClick?: (span: PredictionSpan, disagreementType: string | null) => void;
  onPredictionDismiss?: (span: PredictionSpan, disagreementType: string | null) => void;
}

export interface CandleChartHandle {
  refreshData: () => Promise<void>;
  getVisibleCandles: () => Candle[];
}

const CandleChart = forwardRef<CandleChartHandle, CandleChartProps>(
  ({ 
    activeTool, 
    onAnnotationChange, 
    selectedColor, 
    selectedLabelId, 
    onLabelSelect, 
    activeChartId,
    spanAnnotations = [],
    spanLabelTypes = [],
    selectedSpanId = null,
    onSpanAnnotationsChange,
    onSelectedSpanChange,
    predictionVisible = false,
    perCandlePredictions = [],
    predictionSpans = [],
    confidenceThreshold = 0.5,
    selectedLabels = new Set<string>(),
    modelInfo = null,
    predictionSummary = null,
    showOnlyDisagreements = false,
    onPredictionClick,
    onPredictionDismiss,
  }, ref) => {
    const chartContainerRef = useRef<HTMLDivElement>(null);
    const chartRef = useRef<IChartApi | null>(null);
    const seriesRef = useRef<ISeriesApi<'Candlestick'> | null>(null);
    const histogramSeriesRef = useRef<ISeriesApi<'Histogram'> | null>(null);
    const [candles, setCandles] = useState<Candle[]>([]);
    const [annotations, setAnnotations] = useState<Annotation[]>([]);
    const [annotationTypes, setAnnotationTypes] = useState<AnnotationType[]>([]);
    const [isEmpty, setIsEmpty] = useState(true);
    const { theme, resolvedTheme } = useTheme();
    const [mounted, setMounted] = useState(false);
    
    // Drawing state for line and rectangle tools
    const [drawingState, setDrawingState] = useState<DrawingState | null>(null);
    const previewPrimitiveRef = useRef<TrendLine | RectangleDrawingPrimitive | null>(null);
    const linePrimitivesRef = useRef<Map<number, TrendLine>>(new Map());
    const rectanglePrimitivesRef = useRef<Map<number, RectangleDrawingPrimitive>>(new Map());

    // Track mounted state to avoid hydration mismatch
    useEffect(() => {
      setMounted(true);
    }, []);

    // Fetch candles from API
    const fetchCandles = async () => {
      try {
        const url = activeChartId ? `/api/candles?chartId=${activeChartId}` : '/api/candles';
        const response = await fetch(url);
        const data = await response.json();
        setCandles(data);
        setIsEmpty(data.length === 0);
        return data;
      } catch (error) {
        console.error('Failed to fetch candles:', error);
        return [];
      }
    };

    // Fetch annotations from API
    const fetchAnnotations = async () => {
      try {
        const url = activeChartId ? `/api/annotations?chartId=${activeChartId}` : '/api/annotations';
        const response = await fetch(url);
        const data = await response.json();
        setAnnotations(data);
        return data;
      } catch (error) {
        console.error('Failed to fetch annotations:', error);
        return [];
      }
    };

    // Fetch annotation types from API
    const fetchAnnotationTypes = async () => {
      try {
        const response = await fetch('/api/annotation-types');
        const data = await response.json();
        setAnnotationTypes(data.filter((t: AnnotationType) => t.is_active === 1));
        return data;
      } catch (error) {
        console.error('Failed to fetch annotation types:', error);
        return [];
      }
    };

    // Expose methods to parent
    useImperativeHandle(ref, () => ({
      refreshData: async () => {
        await fetchCandles();
        await fetchAnnotations();
        await fetchAnnotationTypes();
      },
      getVisibleCandles: () => {
        if (!chartRef.current || candles.length === 0) return [];
        const timeScale = chartRef.current.timeScale();
        const visibleRange = timeScale.getVisibleLogicalRange();
        if (!visibleRange) return candles;
        const barsInfo = seriesRef.current?.barsInLogicalRange(visibleRange);
        if (!barsInfo || !barsInfo.barsBefore && !barsInfo.barsAfter) return candles;
        // Filter candles by visible time range
        const from = barsInfo.from as number;
        const to = barsInfo.to as number;
        if (typeof from !== 'number' || typeof to !== 'number') return candles;
        return candles.filter((c) => c.time >= from && c.time <= to);
      },
    }));

    // Get theme-specific colors
    const getChartColors = () => {
      const isDark = resolvedTheme === 'dark';

      if (isDark) {
        return {
          layout: {
            background: { color: '#000000' },
            textColor: '#00ff41',
          },
          grid: {
            vertLines: { color: '#003311' },
            horzLines: { color: '#003311' },
          },
          timeScale: {
            borderColor: '#003311',
          },
          rightPriceScale: {
            borderColor: '#003311',
          },
          crosshair: {
            color: '#00ff41',
          },
        };
      } else {
        return {
          layout: {
            background: { color: '#ffffff' },
            textColor: '#1a1a2e',
          },
          grid: {
            vertLines: { color: '#d1d5db' },
            horzLines: { color: '#d1d5db' },
          },
          timeScale: {
            borderColor: '#d1d5db',
          },
          rightPriceScale: {
            borderColor: '#d1d5db',
          },
          crosshair: {
            color: '#16a34a',
          },
        };
      }
    };

    // Initialize chart
    useEffect(() => {
      if (!chartContainerRef.current || isEmpty || !mounted) return;

      const colors = getChartColors();

      const chart = createChart(chartContainerRef.current, {
        width: chartContainerRef.current.clientWidth,
        height: chartContainerRef.current.clientHeight,
        layout: colors.layout,
        grid: colors.grid,
        crosshair: {
          mode: 1,
        },
        timeScale: {
          timeVisible: true,
          secondsVisible: false,
          borderColor: colors.timeScale.borderColor,
        },
        rightPriceScale: {
          borderColor: colors.rightPriceScale.borderColor,
        },
      });

      const candlestickSeries = chart.addCandlestickSeries({
        upColor: '#ffffff',
        downColor: '#444444',
        borderVisible: true,
        wickUpColor: '#444444',
        wickDownColor: '#444444',
        borderUpColor: '#444444',
        borderDownColor: '#444444',
      });

      // Add histogram series for prediction overlay (rendered behind candles)
      const histogramSeries = chart.addHistogramSeries({
        color: 'rgba(128, 128, 128, 0.15)',
        priceFormat: { type: 'volume' },
        priceScaleId: 'prediction_overlay',
      });
      histogramSeries.priceScale().applyOptions({
        scaleMargins: { top: 0, bottom: 0 },
        visible: false,
      });

      chartRef.current = chart;
      seriesRef.current = candlestickSeries;
      histogramSeriesRef.current = histogramSeries;

      // Handle resize
      const resizeObserver = new ResizeObserver((entries) => {
        if (entries.length === 0 || !chartContainerRef.current) return;
        const { width, height } = entries[0].contentRect;
        chart.applyOptions({ width, height });
      });

      resizeObserver.observe(chartContainerRef.current);

      return () => {
        resizeObserver.disconnect();
        histogramSeriesRef.current = null;
        chart.remove();
      };
    }, [isEmpty, mounted, resolvedTheme]);

    // Load candle data into chart
    useEffect(() => {
      if (!seriesRef.current || candles.length === 0) return;

      const chartData: CandlestickData[] = candles
        .map((candle) => ({
          time: candle.time as Time,
          open: candle.open,
          high: candle.high,
          low: candle.low,
          close: candle.close,
        }))
        .sort((a, b) => (a.time as number) - (b.time as number));

      seriesRef.current.setData(chartData);
    }, [candles]);

    // Update markers from annotations
    useEffect(() => {
      if (!seriesRef.current || annotationTypes.length === 0) return;

      // Get marker type names
      const markerTypeNames = annotationTypes
        .filter((t) => t.category === 'marker')
        .map((t) => t.name);

      const markerAnnotations = annotations.filter((a) =>
        markerTypeNames.includes(a.label_type)
      );

      const markers = markerAnnotations
        .map((annotation) => {
          const annotationType = annotationTypes.find((t) => t.name === annotation.label_type);
          if (!annotationType) return null;

          const isSelected = annotation.id === selectedLabelId;

          // Determine marker shape and position based on icon
          const isUpArrow = annotationType.icon === 'arrowUp';

          return {
            time: annotation.timestamp as Time,
            position: isUpArrow ? ('belowBar' as const) : ('aboveBar' as const),
            color: isSelected
              ? annotationType.color + 'CC' // Add slight transparency when selected
              : annotationType.color,
            shape: isUpArrow ? ('arrowUp' as const) : ('arrowDown' as const),
            text: annotationType.display_name,
            size: isSelected ? 2 : 1,
          };
        })
        .filter((m) => m !== null)
        .sort((a, b) => (a!.time as number) - (b!.time as number));

      seriesRef.current.setMarkers(markers as any);
    }, [annotations, selectedLabelId, annotationTypes]);

    // Render prediction histogram overlay and span markers
    useEffect(() => {
      if (!histogramSeriesRef.current || !seriesRef.current || candles.length === 0) return;

      // If predictions are not visible or no data, clear the histogram and markers
      if (!predictionVisible || perCandlePredictions.length === 0) {
        histogramSeriesRef.current.setData([]);
        histogramSeriesRef.current.setMarkers([]);
        return;
      }

      // Build a label-to-color map from modelInfo
      // Generate colors for labels since backend no longer provides them
      const labelColorMap: Record<string, string> = {};
      if (modelInfo?.labels) {
        const predefinedColors = [
          '#3b82f6', // blue
          '#ef4444', // red
          '#10b981', // green
          '#f59e0b', // amber
          '#8b5cf6', // violet
          '#ec4899', // pink
          '#06b6d4', // cyan
          '#f97316', // orange
        ];
        modelInfo.labels.forEach((label, index) => {
          labelColorMap[label] = predefinedColors[index % predefinedColors.length];
        });
      }

      // Build disagreement lookup map for highlighting
      // Map: predictionSpan start_time -> disagreement type
      const disagreementMap = new Map<number, string>();
      const disagreementSpanSet = new Set<string>(); // Set of "start-end" keys for filtering
      
      if (predictionSummary?.disagreements) {
        predictionSummary.disagreements.forEach((d) => {
          if (d.predictionSpan) {
            disagreementMap.set(d.predictionSpan.start_time, d.type);
            disagreementSpanSet.add(`${d.predictionSpan.start_time}-${d.predictionSpan.end_time}`);
          }
        });
      }

      // Helper to convert hex to rgba
      const hexToRgba = (hex: string, alpha: number): string => {
        hex = hex.replace('#', '');
        const r = parseInt(hex.substring(0, 2), 16);
        const g = parseInt(hex.substring(2, 4), 16);
        const b = parseInt(hex.substring(4, 6), 16);
        return `rgba(${r}, ${g}, ${b}, ${alpha})`;
      };

      // Build candle price lookup for histogram values
      const candleMap = new Map(candles.map((c) => [c.time, c]));

      // Build a map from prediction time to its span for disagreement lookup
      const predictionTimeToSpan = new Map<number, PredictionSpan>();
      predictionSpans.forEach((span) => {
        // Associate all times in the span with the span object
        for (let t = span.start_time; t <= span.end_time; t += 60) { // Assuming 1-minute candles, adjust if needed
          predictionTimeToSpan.set(t, span);
        }
      });

      // Filter and map predictions to histogram data with disagreement highlighting
      const histogramData: (HistogramData & { color?: string })[] = perCandlePredictions
        .filter((p) => {
          // Filter by confidence threshold
          if (p.confidence < confidenceThreshold) return false;
          // Filter by selected labels
          if (!selectedLabels.has(p.label)) return false;
          // Skip "O" (no-pattern) labels
          if (p.label === 'O') return false;

          // If showOnlyDisagreements is enabled, only show predictions that are part of disagreements
          if (showOnlyDisagreements) {
            const span = predictionTimeToSpan.get(p.time);
            if (!span) return false;
            const spanKey = `${span.start_time}-${span.end_time}`;
            if (!disagreementSpanSet.has(spanKey)) return false;
          }

          return true;
        })
        .map((p) => {
          const candle = candleMap.get(p.time);
          // Use candle high as the histogram value so it overlays correctly
          const value = candle ? candle.high : 0;
          
          // Check if this prediction is part of a disagreement
          const span = predictionTimeToSpan.get(p.time);
          const disagreementType = span ? disagreementMap.get(span.start_time) : null;
          
          let baseColor = labelColorMap[p.label] || '#888888';
          let alpha = 0.15;
          
          // Apply disagreement-specific colors and styling
          if (disagreementType === 'missed_by_human') {
            // Yellow highlight for predictions missed by humans
            baseColor = '#eab308'; // yellow
            alpha = 0.25;
          } else if (disagreementType === 'label_mismatch') {
            // Orange for label mismatches
            baseColor = '#f97316'; // orange
            alpha = 0.25;
          }
          
          return {
            time: p.time as Time,
            value,
            color: hexToRgba(baseColor, alpha),
          };
        })
        .sort((a, b) => (a.time as number) - (b.time as number));

      histogramSeriesRef.current.setData(histogramData);

      // Add markers for prediction span labels at span start times
      const spanMarkers: SeriesMarker<Time>[] = predictionSpans
        .filter((span) => {
          if (span.avg_confidence < confidenceThreshold) return false;
          if (!selectedLabels.has(span.label)) return false;
          if (span.label === 'O') return false;

          // If showOnlyDisagreements is enabled, only show spans that are disagreements
          if (showOnlyDisagreements) {
            const spanKey = `${span.start_time}-${span.end_time}`;
            if (!disagreementSpanSet.has(spanKey)) return false;
          }

          return true;
        })
        .map((span) => {
          const disagreementType = disagreementMap.get(span.start_time);
          let baseColor = labelColorMap[span.label] || '#888888';
          let labelText = span.label;
          
          // Apply disagreement-specific styling to markers
          if (disagreementType === 'missed_by_human') {
            baseColor = '#eab308'; // yellow
            labelText = `⚠ ${span.label}`;
          } else if (disagreementType === 'label_mismatch') {
            baseColor = '#f97316'; // orange
            labelText = `⚠ ${span.label}`;
          }
          
          const confidencePct = Math.round(span.avg_confidence * 100);
          return {
            time: span.start_time as Time,
            position: 'belowBar' as const,
            color: baseColor,
            shape: 'square' as const,
            text: `${labelText} (${confidencePct}%)`,
            size: 1,
          };
        })
        .sort((a, b) => (a.time as number) - (b.time as number));

      histogramSeriesRef.current.setMarkers(spanMarkers);
    }, [predictionVisible, perCandlePredictions, predictionSpans, confidenceThreshold, selectedLabels, modelInfo, candles, predictionSummary, showOnlyDisagreements]);

    // Handle chart clicks for annotation
    useEffect(() => {
      if (!chartRef.current || !seriesRef.current) return;

      const handleClick = async (param: any) => {
        if (!param.point) return;

        const timeCoordinate = param.point.x;
        const priceCoordinate = param.point.y;

        const time = chartRef.current!.timeScale().coordinateToTime(timeCoordinate);
        const price = seriesRef.current!.coordinateToPrice(priceCoordinate);

        if (time === null || price === null) return;

        // Handle line and rectangle drawing
        if (activeTool === 'line' || activeTool === 'rectangle') {
          if (!drawingState) {
            // First click: record first point and show preview
            const firstPoint = { time, price };
            setDrawingState({ tool: activeTool, firstPoint });

            // Create preview primitive
            if (seriesRef.current && chartRef.current) {
              const previewPoint = { time, price };
              
              if (activeTool === 'line') {
                const preview = new TrendLine(
                  chartRef.current,
                  seriesRef.current,
                  firstPoint as Point,
                  previewPoint as Point,
                  {
                    lineColor: selectedColor,
                    width: 2,
                    showLabels: false,
                    isPreview: true,
                  }
                );
                seriesRef.current.attachPrimitive(preview);
                previewPrimitiveRef.current = preview;
              } else {
                const preview = new RectangleDrawingPrimitive({
                  p1: firstPoint as RectanglePoint,
                  p2: previewPoint as RectanglePoint,
                  color: selectedColor,
                  isPreview: true,
                });
                seriesRef.current.attachPrimitive(preview);
                previewPrimitiveRef.current = preview;
              }
            }
          } else {
            // Second click: save annotation and create permanent primitive
            const secondPoint = { time, price };
            
            try {
              const timestamp = typeof drawingState.firstPoint.time === 'string' 
                ? Date.parse(drawingState.firstPoint.time) / 1000 
                : (drawingState.firstPoint.time as number);
              
              const response = await fetch('/api/annotations', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                  timestamp,
                  label_type: activeTool,
                  chart_id: activeChartId,
                  color: selectedColor,
                  geometry: {
                    startTime: typeof drawingState.firstPoint.time === 'string' 
                      ? Date.parse(drawingState.firstPoint.time) / 1000 
                      : drawingState.firstPoint.time,
                    startPrice: drawingState.firstPoint.price,
                    endTime: typeof secondPoint.time === 'string' 
                      ? Date.parse(secondPoint.time) / 1000 
                      : secondPoint.time,
                    endPrice: secondPoint.price,
                  },
                }),
              });

              if (response.ok) {
                // Detach preview
                if (previewPrimitiveRef.current && seriesRef.current) {
                  seriesRef.current.detachPrimitive(previewPrimitiveRef.current);
                  previewPrimitiveRef.current = null;
                }

                // Clear drawing state
                setDrawingState(null);

                // Refresh annotations to load the permanent primitive
                await fetchAnnotations();
                onAnnotationChange?.();
              }
            } catch (error) {
              console.error('Failed to create annotation:', error);
            }
          }
          return; // Don't process other tools
        }

        if (!activeTool) return;

        // Check if activeTool is a marker type
        const markerType = annotationTypes.find(
          (t) => t.category === 'marker' && t.name === activeTool
        );

        if (markerType) {
          const timestamp = typeof time === 'string' ? Date.parse(time) / 1000 : (time as number);

          // Find nearest candle
          const nearestCandle = candles.reduce((prev, curr) => {
            return Math.abs(curr.time - timestamp) < Math.abs(prev.time - timestamp) ? curr : prev;
          }, candles[0]);

          if (!nearestCandle) return;

          // Create annotation
          try {
            const response = await fetch('/api/annotations', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({
                timestamp: nearestCandle.time,
                label_type: activeTool,
                chart_id: activeChartId,
              }),
            });

            if (response.ok) {
              await fetchAnnotations();
              onAnnotationChange?.();
            }
          } catch (error) {
            console.error('Failed to create annotation:', error);
          }
        }

        // For delete tool, find and delete marker at clicked position
        if (activeTool === 'delete') {
          const timestamp = typeof time === 'string' ? Date.parse(time) / 1000 : (time as number);
          const markerTypeNames = annotationTypes
            .filter((t) => t.category === 'marker')
            .map((t) => t.name);

          // Find annotation at this timestamp (within tolerance)
          const tolerance = 60; // 60 seconds tolerance
          const annotation = annotations.find(
            (a) =>
              markerTypeNames.includes(a.label_type) &&
              Math.abs(a.timestamp - timestamp) < tolerance
          );

          if (annotation) {
            try {
              const response = await fetch(`/api/annotations/${annotation.id}`, {
                method: 'DELETE',
              });

              if (response.ok) {
                await fetchAnnotations();
                onAnnotationChange?.();
              }
            } catch (error) {
              console.error('Failed to delete annotation:', error);
            }
          }
        }

        // Handle clicks on prediction spans (for converting to annotations or dismissing)
        if (!activeTool && predictionVisible && predictionSpans.length > 0) {
          const timestamp = typeof time === 'string' ? Date.parse(time) / 1000 : (time as number);
          
          // Find if click is within any prediction span
          const clickedSpan = predictionSpans.find(
            (span) => timestamp >= span.start_time && timestamp <= span.end_time
          );

          if (clickedSpan) {
            // Check if this span is a disagreement
            const disagreementMap = new Map<number, string>();
            if (predictionSummary?.disagreements) {
              predictionSummary.disagreements.forEach((d) => {
                if (d.predictionSpan) {
                  disagreementMap.set(d.predictionSpan.start_time, d.type);
                }
              });
            }

            const disagreementType = disagreementMap.get(clickedSpan.start_time) || null;
            
            // Check if Alt or Ctrl key is pressed for dismiss action
            if ((param.sourceEvent?.altKey || param.sourceEvent?.ctrlKey) && onPredictionDismiss) {
              // Alt+Click or Ctrl+Click: Dismiss as "not a pattern"
              onPredictionDismiss(clickedSpan, disagreementType);
            } else if (onPredictionClick) {
              // Normal click: Convert to annotation (only for disagreements)
              if (disagreementType === 'missed_by_human' || disagreementType === 'label_mismatch') {
                onPredictionClick(clickedSpan, disagreementType);
              }
            }
          }
        }

        // Select/deselect label markers by clicking them
        const isMarkerTool = annotationTypes.find(
          (t) => t.category === 'marker' && t.name === activeTool
        );

        if (!activeTool || isMarkerTool) {
          const timestamp = typeof time === 'string' ? Date.parse(time) / 1000 : (time as number);
          const markerTypeNames = annotationTypes
            .filter((t) => t.category === 'marker')
            .map((t) => t.name);

          // Find annotation at this timestamp (within tolerance)
          const tolerance = 60; // 60 seconds tolerance
          const annotation = annotations.find(
            (a) =>
              markerTypeNames.includes(a.label_type) &&
              Math.abs(a.timestamp - timestamp) < tolerance
          );

          if (annotation) {
            onLabelSelect?.(annotation.id === selectedLabelId ? -1 : annotation.id);
          }
        }
      };

      chartRef.current.subscribeClick(handleClick);

      return () => {
        chartRef.current?.unsubscribeClick(handleClick);
      };
    }, [activeTool, candles, annotations, annotationTypes, onAnnotationChange, predictionVisible, predictionSpans, predictionSummary, onPredictionClick, onPredictionDismiss, drawingState, selectedColor]);

    // Handle crosshair move to update preview during drawing
    useEffect(() => {
      if (!chartRef.current || !seriesRef.current || !drawingState || !previewPrimitiveRef.current) return;

      const handleCrosshairMove = (param: any) => {
        if (!param.point) return;

        const time = chartRef.current!.timeScale().coordinateToTime(param.point.x);
        const price = seriesRef.current!.coordinateToPrice(param.point.y);

        if (time === null || price === null) return;

        const currentPoint = { time, price };

        // Update preview primitive endpoint
        if (previewPrimitiveRef.current) {
          if (previewPrimitiveRef.current instanceof TrendLine) {
            previewPrimitiveRef.current.updatePoints(
              drawingState.firstPoint as Point,
              currentPoint as Point
            );
          } else if (previewPrimitiveRef.current instanceof RectangleDrawingPrimitive) {
            previewPrimitiveRef.current.updatePoints(
              drawingState.firstPoint as RectanglePoint,
              currentPoint as RectanglePoint
            );
          }
          seriesRef.current!.applyOptions({});
        }
      };

      chartRef.current.subscribeCrosshairMove(handleCrosshairMove);

      return () => {
        chartRef.current?.unsubscribeCrosshairMove(handleCrosshairMove);
      };
    }, [drawingState]);

    // Handle Escape key to cancel drawing
    useEffect(() => {
      const handleKeyDown = (e: KeyboardEvent) => {
        if (e.key === 'Escape' && drawingState && previewPrimitiveRef.current) {
          // Detach preview primitive
          if (seriesRef.current) {
            seriesRef.current.detachPrimitive(previewPrimitiveRef.current);
            previewPrimitiveRef.current = null;
          }
          // Clear drawing state
          setDrawingState(null);
        }
      };

      window.addEventListener('keydown', handleKeyDown);

      return () => {
        window.removeEventListener('keydown', handleKeyDown);
      };
    }, [drawingState]);

    // Manage TrendLine primitives for saved line annotations
    useEffect(() => {
      if (!chartRef.current || !seriesRef.current || annotations.length === 0) return;

      // Filter line annotations
      const lineAnnotations = annotations.filter((a) => a.label_type === 'line' && a.geometry);

      // Detach old primitives that no longer exist
      const currentIds = new Set(lineAnnotations.map((a) => a.id));
      linePrimitivesRef.current.forEach((primitive, id) => {
        if (!currentIds.has(id)) {
          seriesRef.current!.detachPrimitive(primitive);
          linePrimitivesRef.current.delete(id);
        }
      });

      // Create/update primitives for line annotations
      lineAnnotations.forEach((annotation) => {
        const geometry = annotation.geometry!;
        if (!geometry.startTime || !geometry.endTime) return;

        // Check if primitive already exists
        if (!linePrimitivesRef.current.has(annotation.id)) {
          // Create new TrendLine primitive
          const p1: Point = {
            time: geometry.startTime as Time,
            price: geometry.startPrice!,
          };
          const p2: Point = {
            time: geometry.endTime as Time,
            price: geometry.endPrice!,
          };

          const color = annotationTypes.find((t) => t.name === 'line')?.color || selectedColor;

          const trendLine = new TrendLine(
            chartRef.current!,
            seriesRef.current!,
            p1,
            p2,
            {
              lineColor: color,
              width: 2,
              showLabels: false,
              annotationId: String(annotation.id),
            }
          );

          seriesRef.current!.attachPrimitive(trendLine);
          linePrimitivesRef.current.set(annotation.id, trendLine);
        }
      });
    }, [annotations, annotationTypes, selectedColor]);

    // Fetch data on mount
    useEffect(() => {
      fetchCandles();
      fetchAnnotations();
      fetchAnnotationTypes();
    }, []);

    if (isEmpty) {
      return (
        <div className="flex-1 flex items-center justify-center bg-background">
          <div className="text-muted-foreground text-center">
            <p className="text-lg">Upload a CSV file to view the candlestick chart</p>
            <p className="text-sm mt-2">CSV format: time, open, high, low, close</p>
          </div>
        </div>
      );
    }

    return (
      <div className="w-full h-full relative">
        <div ref={chartContainerRef} className="absolute inset-0" />
        <SvgOverlay
          chart={chartRef.current}
          series={seriesRef.current}
          activeTool={activeTool}
          onAnnotationChange={onAnnotationChange}
          selectedColor={selectedColor}
          activeChartId={activeChartId}
        />
        <SpanAnnotationManager
          chart={chartRef.current}
          series={seriesRef.current}
          activeTool={activeTool}
          candles={candles}
          spanAnnotations={spanAnnotations}
          spanLabelTypes={spanLabelTypes}
          selectedSpanId={selectedSpanId}
          onSpanAnnotationsChange={onSpanAnnotationsChange || (() => {})}
          onSelectedSpanChange={onSelectedSpanChange || (() => {})}
          activeChartId={activeChartId ?? null}
        />
      </div>
    );
  }
);

CandleChart.displayName = 'CandleChart';

export default CandleChart;
