import * as LightweightCharts from 'lightweight-charts';
import { useEffect, useRef, useCallback, useMemo } from 'react';
import { useChartManager } from '@/hooks/useChartManager';

export interface ChartData {
  time: number;
  open?: number;
  high?: number;
  low?: number;
  close?: number;
  value?: number;
  volume?: number;
}

export interface TradeMarker {
  time: number;
  position: 'aboveBar' | 'belowBar';
  color: string;
  shape: 'arrowUp' | 'arrowDown';
  text: string;
  id?: string;
  price?: number;
}

export interface ChartProps {
  data: ChartData[];
  height?: number | string;
  type?: 'candlestick' | 'line' | 'area';
  showVolume?: boolean;
  theme?: 'light' | 'dark';
  overlayData?: Array<{
    name: string;
    data: Array<{ time: number; value: number }>;
    color?: string;
    lineWidth?: number;
  }>;
  tradeMarkers?: TradeMarker[];
  className?: string;
  chartId?: string;
}

export function Chart({
  data,
  height = 400,
  type = 'candlestick',
  showVolume = true,
  theme = 'dark',
  overlayData = [],
  tradeMarkers = [],
  className = '',
  chartId = 'default',
}: ChartProps) {
  const chartContainerRef = useRef<HTMLDivElement>(null);
  const { createChart, getChart, setMainSeries, setVolumeSeries, addOverlaySeries, disposeChart } = useChartManager();
  
  // Use a stable unique ID that changes only when chartId prop changes
  const uniqueChartId = useMemo(() => {
    return `${chartId}-${Date.now()}`;
  }, [chartId])
  const mountedRef = useRef(true);
  const lastChartIdRef = useRef(chartId);
  
  // Track component mount state
  useEffect(() => {
    mountedRef.current = true;
    return () => {
      mountedRef.current = false;
      // Cleanup on unmount
      disposeChart(uniqueChartId);
    };
  }, [disposeChart]);
  
  // Reset zoom handler
  const resetZoom = useCallback(() => {
    const chartInstance = getChart(uniqueChartId);
    if (chartInstance && !chartInstance.isDisposed && data.length > 0) {
      // Get the validated data to ensure we're using the correct time values
      const validateData = (rawData: any[]) => {
        const seen = new Set<number>();
        return rawData
          .map(item => {
            const timeInSeconds = item.time > 10000000000 
              ? Math.floor(item.time / 1000) 
              : item.time;
            return { ...item, time: timeInSeconds };
          })
          .filter(item => {
            if (seen.has(item.time)) return false;
            seen.add(item.time);
            return true;
          })
          .sort((a, b) => a.time - b.time);
      };
      
      const validatedData = validateData(data);
      
      if (validatedData.length > 0) {
        const firstTime = validatedData[0].time;
        const lastTime = validatedData[validatedData.length - 1].time;
        
        // Add some padding (5% on each side)
        const timeRange = lastTime - firstTime;
        const padding = timeRange * 0.05;
        
        try {
          chartInstance.chart.timeScale().setVisibleRange({
            from: (firstTime - padding) as any,
            to: (lastTime + padding) as any,
          });
          
          chartInstance.chart.timeScale().fitContent();
        } catch (error) {
          console.error('Error resetting zoom:', error);
        }
      }
    }
  }, [data, getChart]);

  useEffect(() => {
    if (!chartContainerRef.current || !data || !data.length) {
      return;
    }
    
    let handleResize: (() => void) | undefined;
    let isCleanedUp = false;
    
    // Use requestAnimationFrame to ensure DOM is ready and avoid conflicts
    const rafId = requestAnimationFrame(() => {
      const initTimeout = setTimeout(() => {
        if (!chartContainerRef.current || isCleanedUp || !mountedRef.current) return;

        // Create chart using the chart manager
        const chart = createChart(uniqueChartId, chartContainerRef.current, {
      width: chartContainerRef.current.clientWidth,
      height: height,
      layout: {
        background: { 
          type: LightweightCharts.ColorType.Solid, 
          color: theme === 'dark' ? '#0f0f0f' : '#ffffff' 
        },
        textColor: theme === 'dark' ? '#d1d5db' : '#374151',
      },
      grid: {
        vertLines: {
          color: theme === 'dark' ? '#1f2937' : '#e5e7eb',
          visible: true,
        },
        horzLines: {
          color: theme === 'dark' ? '#1f2937' : '#e5e7eb',
          visible: true,
        },
      },
      crosshair: {
        mode: LightweightCharts.CrosshairMode.Normal,
      },
      rightPriceScale: {
        borderColor: theme === 'dark' ? '#1f2937' : '#e5e7eb',
        autoScale: true,
      },
      timeScale: {
        borderColor: theme === 'dark' ? '#1f2937' : '#e5e7eb',
        timeVisible: true,
        secondsVisible: false,
        rightOffset: 12,
        barSpacing: 3,
        fixLeftEdge: true,
        fixRightEdge: true,
      },
    });

    if (!chart) {
      console.error('Failed to create chart');
      return;
    }

    // Filter, validate and sort data
    const validateAndFilterData = (rawData: any[]) => {
      const seen = new Set<number>();
      return rawData
        .map(item => {
          // Convert timestamp to seconds if it's in milliseconds
          const timeInSeconds = item.time > 10000000000 
            ? Math.floor(item.time / 1000) 
            : item.time;
          
          return {
            ...item,
            time: timeInSeconds as LightweightCharts.Time
          };
        })
        .filter((item, index) => {
          if (seen.has(item.time)) {
            return false;
          }
          seen.add(item.time);
          return true;
        })
        .sort((a, b) => (a.time as number) - (b.time as number)); // Ensure ascending time order
    };

    // Create main series
    let mainSeries: LightweightCharts.ISeriesApi<any> | null = null;
    
    if (type === 'candlestick' && data[0].open !== undefined) {
      mainSeries = chart.addCandlestickSeries({
        upColor: '#10b981',
        downColor: '#ef4444',
        borderUpColor: '#10b981',
        borderDownColor: '#ef4444',
        wickUpColor: '#10b981',
        wickDownColor: '#ef4444',
      });
      const validData = validateAndFilterData(data);
      mainSeries.setData(validData as LightweightCharts.CandlestickData[]);
    } else if (type === 'line' || (type === 'candlestick' && data[0].value !== undefined)) {
      mainSeries = chart.addLineSeries({
        color: '#3b82f6',
        lineWidth: 2,
      });
      const lineData = data.map(d => ({
        time: d.time,
        value: d.value ?? d.close ?? 0
      }));
      const validData = validateAndFilterData(lineData);
      mainSeries.setData(validData);
    } else if (type === 'area') {
      mainSeries = chart.addAreaSeries({
        lineColor: '#3b82f6',
        topColor: '#3b82f6',
        bottomColor: 'rgba(59, 130, 246, 0.1)',
        lineWidth: 2,
      });
      const areaData = data.map(d => ({
        time: d.time,
        value: d.value ?? d.close ?? 0
      }));
      const validData = validateAndFilterData(areaData);
      mainSeries.setData(validData);
    }
    
    if (mainSeries) {
      setMainSeries(uniqueChartId, mainSeries);
    }

    // Add volume if available
    if (showVolume && data.some(d => d.volume)) {
      const volumeSeries = chart.addHistogramSeries({
        color: '#3b82f680',
        priceFormat: {
          type: 'volume',
        },
        priceScaleId: 'volume',
      });
      
      volumeSeries.priceScale().applyOptions({
        scaleMargins: {
          top: 0.8,
          bottom: 0,
        },
      });

      const volumeData = validateAndFilterData(
        data
          .filter(d => d.volume !== undefined)
          .map(d => ({
            time: d.time,
            value: d.volume!,
            color: d.close && d.open ? 
              (d.close >= d.open ? '#10b98140' : '#ef444440') : 
              '#3b82f640',
          }))
      );
      volumeSeries.setData(volumeData);
      setVolumeSeries(uniqueChartId, volumeSeries);
    }

    // Add overlay series
    overlayData.forEach((overlay, index) => {
      const series = chart.addLineSeries({
        color: overlay.color || ['#ff9800', '#4caf50', '#9c27b0', '#f44336'][index % 4],
        lineWidth: overlay.lineWidth || 2,
        title: overlay.name,
        priceScaleId: index === 0 ? '' : `overlay-${index}`, // First overlay uses main scale
      });
      
      if (index > 0) {
        series.priceScale().applyOptions({
          scaleMargins: {
            top: 0.1,
            bottom: 0.1,
          },
        });
      }
      
      // Use validateAndFilterData to ensure consistent time handling
      const overlayDataWithTime = overlay.data.map(d => ({
        ...d,
        time: d.time // Ensure time field exists
      }));
      const validatedData = validateAndFilterData(overlayDataWithTime);
      series.setData(validatedData);
      addOverlaySeries(uniqueChartId, overlay.name, series);
    });

    // Add trade markers
    if (tradeMarkers.length > 0 && mainSeries) {
      // Sort markers by time to ensure they're in ascending order
      const sortedMarkers = [...tradeMarkers].sort((a, b) => a.time - b.time);
      const markers: LightweightCharts.SeriesMarker<LightweightCharts.Time>[] = sortedMarkers.map(marker => ({
        time: marker.time as LightweightCharts.Time,
        position: marker.position,
        color: marker.color,
        shape: marker.shape as LightweightCharts.SeriesMarkerShape,
        text: marker.text,
        id: marker.id,
        size: 1
      }));
      mainSeries.setMarkers(markers);
    }

    // Fit content with a slight delay to ensure all series are loaded
    setTimeout(() => {
      // First fit content to calculate proper range
      chart.timeScale().fitContent();
      
      // Get the validated data to ensure we're using the correct time values
      const validatedData = validateAndFilterData(data);
      
      // Set visible range with some padding
      if (validatedData.length > 0) {
        const firstTime = validatedData[0].time;
        const lastTime = validatedData[validatedData.length - 1].time;
        
        // Add some padding (5% on each side)
        const timeRange = (lastTime as number) - (firstTime as number);
        const padding = timeRange * 0.05;
        
        chart.timeScale().setVisibleRange({
          from: ((firstTime as number) - padding) as any,
          to: ((lastTime as number) + padding) as any,
        });
      }
      
      // Ensure the chart fits the content properly
      chart.timeScale().fitContent();
    }, 100);
    
    // Enable mouse wheel zoom and touch gestures
    chart.applyOptions({
      handleScroll: {
        mouseWheel: true,
        pressedMouseMove: true,
        horzTouchDrag: true,
        vertTouchDrag: true,
      },
      handleScale: {
        mouseWheel: true,
        pinch: true,
        axisPressedMouseMove: true,
      },
    });

    // Handle resize
    handleResize = () => {
      if (chartContainerRef.current && !isCleanedUp) {
        const chartInstance = getChart(uniqueChartId);
        if (chartInstance && !chartInstance.isDisposed) {
          try {
            chartInstance.chart.applyOptions({
              width: chartContainerRef.current.clientWidth,
            });
          } catch (error) {
            // Ignore errors if the chart is being disposed
            if (!error?.message?.includes('disposed')) {
              console.error('Error resizing chart:', error);
            }
          }
        }
      }
    };

    window.addEventListener('resize', handleResize);
      }, 0); // End of setTimeout
    }); // End of requestAnimationFrame

    // Cleanup
    return () => {
      isCleanedUp = true;
      cancelAnimationFrame(rafId);
      if (handleResize) {
        window.removeEventListener('resize', handleResize);
      }
      // Dispose immediately - the chart manager handles cleanup safely
      disposeChart(uniqueChartId);
    };
  }, [data, height, type, showVolume, theme, overlayData, tradeMarkers, createChart, getChart, setMainSeries, setVolumeSeries, addOverlaySeries, disposeChart]);

  return (
    <div className={`relative ${className}`}>
      <div 
        ref={chartContainerRef} 
        style={{ 
          width: '100%', 
          height: typeof height === 'string' ? height : `${height}px` 
        }}
      />
      <button
        onClick={resetZoom}
        className="absolute top-2 right-2 px-2 py-1 text-xs bg-surface-primary border border-border rounded hover:bg-surface-secondary transition-colors"
        title="Reset zoom"
      >
        Reset Zoom
      </button>
    </div>
  );
}