import React, { useRef, useEffect } from 'react';

export type ChartType = 'line' | 'bar' | 'area' | 'pie' | 'doughnut';

export interface ChartDataPoint {
  x: string | number;
  y: number;
  label?: string;
  color?: string;
}

export interface ChartSeries {
  id: string;
  name: string;
  type: ChartType;
  data: ChartDataPoint[];
  color: string;
  visible?: boolean;
}

export interface AnalyticsChartProps {
  series: ChartSeries[];
  height?: number;
  className?: string;
  showLegend?: boolean;
  showGrid?: boolean;
  animate?: boolean;
}

export const AnalyticsChart: React.FC<AnalyticsChartProps> = ({
  series,
  height = 300,
  className = '',
  showLegend = true,
  showGrid = true,
  animate = true
}) => {
  const canvasRef = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    if (!canvasRef.current || series.length === 0) return;

    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    // Set canvas size
    const rect = canvas.getBoundingClientRect();
    const dpr = window.devicePixelRatio || 1;
    canvas.width = rect.width * dpr;
    canvas.height = rect.height * dpr;
    ctx.scale(dpr, dpr);

    // Clear canvas
    ctx.clearRect(0, 0, rect.width, rect.height);

    // Chart settings
    const padding = 40;
    const chartWidth = rect.width - 2 * padding;
    const chartHeight = rect.height - 2 * padding - (showLegend ? 40 : 0);

    // Get visible series
    const visibleSeries = series.filter(s => s.visible !== false);
    if (visibleSeries.length === 0) return;

    // Draw based on chart type
    const primarySeries = visibleSeries[0];

    if (primarySeries.type === 'pie' || primarySeries.type === 'doughnut') {
      drawPieChart(ctx, primarySeries, rect.width, rect.height - (showLegend ? 40 : 0));
    } else {
      drawCartesianChart(ctx, visibleSeries, padding, chartWidth, chartHeight, showGrid);
    }

    // Draw legend
    if (showLegend) {
      drawLegend(ctx, visibleSeries, rect.width, rect.height);
    }
  }, [series, height, showLegend, showGrid]);

  const drawPieChart = (ctx: CanvasRenderingContext2D, series: ChartSeries, width: number, height: number) => {
    const centerX = width / 2;
    const centerY = height / 2;
    const radius = Math.min(width, height) / 3;
    const innerRadius = series.type === 'doughnut' ? radius * 0.6 : 0;

    const total = series.data.reduce((sum, point) => sum + point.y, 0);
    let startAngle = -Math.PI / 2;

    series.data.forEach((point, index) => {
      const sliceAngle = (point.y / total) * 2 * Math.PI;
      const color = point.color || series.color || getDefaultColor(index);

      // Draw slice
      ctx.fillStyle = color;
      ctx.beginPath();
      ctx.moveTo(centerX, centerY);
      ctx.arc(centerX, centerY, radius, startAngle, startAngle + sliceAngle);
      if (innerRadius > 0) {
        ctx.arc(centerX, centerY, innerRadius, startAngle + sliceAngle, startAngle, true);
      }
      ctx.closePath();
      ctx.fill();

      // Draw slice border
      ctx.strokeStyle = '#ffffff';
      ctx.lineWidth = 2;
      ctx.stroke();

      // Draw labels
      const labelAngle = startAngle + sliceAngle / 2;
      const labelRadius = radius + 20;
      const labelX = centerX + Math.cos(labelAngle) * labelRadius;
      const labelY = centerY + Math.sin(labelAngle) * labelRadius;

      ctx.fillStyle = '#374151';
      ctx.font = '12px sans-serif';
      ctx.textAlign = 'center';
      ctx.fillText(point.label || point.x.toString(), labelX, labelY);

      const percentage = ((point.y / total) * 100).toFixed(1);
      ctx.fillText(`${percentage}%`, labelX, labelY + 15);

      startAngle += sliceAngle;
    });

    // Draw center label for doughnut
    if (series.type === 'doughnut') {
      ctx.fillStyle = '#374151';
      ctx.font = 'bold 16px sans-serif';
      ctx.textAlign = 'center';
      ctx.fillText(total.toString(), centerX, centerY - 5);
      ctx.font = '12px sans-serif';
      ctx.fillText('Total', centerX, centerY + 10);
    }
  };

  const drawCartesianChart = (
    ctx: CanvasRenderingContext2D,
    seriesList: ChartSeries[],
    padding: number,
    chartWidth: number,
    chartHeight: number,
    showGrid: boolean
  ) => {
    // Get all data points to determine scales
    const allData = seriesList.flatMap(s => s.data);
    const maxY = Math.max(...allData.map(d => d.y));
    const minY = Math.min(0, Math.min(...allData.map(d => d.y)));

    // Draw grid
    if (showGrid) {
      ctx.strokeStyle = '#e2e8f0';
      ctx.lineWidth = 1;

      // Horizontal grid lines
      for (let i = 0; i <= 5; i++) {
        const y = padding + (i * chartHeight) / 5;
        ctx.beginPath();
        ctx.moveTo(padding, y);
        ctx.lineTo(padding + chartWidth, y);
        ctx.stroke();

        // Y-axis labels
        const value = maxY - (i * (maxY - minY)) / 5;
        ctx.fillStyle = '#64748b';
        ctx.font = '12px sans-serif';
        ctx.textAlign = 'right';
        ctx.fillText(Math.round(value).toString(), padding - 10, y + 4);
      }
    }

    // Draw axes
    ctx.strokeStyle = '#374151';
    ctx.lineWidth = 2;
    ctx.beginPath();
    ctx.moveTo(padding, padding);
    ctx.lineTo(padding, padding + chartHeight);
    ctx.lineTo(padding + chartWidth, padding + chartHeight);
    ctx.stroke();

    // Draw each series
    seriesList.forEach((series, seriesIndex) => {
      ctx.strokeStyle = series.color || getDefaultColor(seriesIndex);
      ctx.fillStyle = series.color || getDefaultColor(seriesIndex);

      if (series.type === 'line') {
        drawLineChart(ctx, series, padding, chartWidth, chartHeight, maxY, minY);
      } else if (series.type === 'bar') {
        drawBarChart(ctx, series, padding, chartWidth, chartHeight, maxY, minY, seriesIndex, seriesList.length);
      } else if (series.type === 'area') {
        drawAreaChart(ctx, series, padding, chartWidth, chartHeight, maxY, minY);
      }
    });
  };

  const drawLineChart = (
    ctx: CanvasRenderingContext2D,
    series: ChartSeries,
    padding: number,
    chartWidth: number,
    chartHeight: number,
    maxY: number,
    minY: number
  ) => {
    if (series.data.length === 0) return;

    ctx.lineWidth = 3;
    ctx.beginPath();

    series.data.forEach((point, index) => {
      const x = padding + (index * chartWidth) / (series.data.length - 1 || 1);
      const y = padding + chartHeight - ((point.y - minY) / (maxY - minY)) * chartHeight;

      if (index === 0) {
        ctx.moveTo(x, y);
      } else {
        ctx.lineTo(x, y);
      }

      // Draw points
      ctx.fillStyle = ctx.strokeStyle;
      ctx.beginPath();
      ctx.arc(x, y, 4, 0, 2 * Math.PI);
      ctx.fill();
    });

    ctx.stroke();
  };

  const drawBarChart = (
    ctx: CanvasRenderingContext2D,
    series: ChartSeries,
    padding: number,
    chartWidth: number,
    chartHeight: number,
    maxY: number,
    minY: number,
    seriesIndex: number,
    totalSeries: number
  ) => {
    const barGroupWidth = chartWidth / series.data.length;
    const barWidth = barGroupWidth / totalSeries - 4;

    series.data.forEach((point, index) => {
      const x = padding + index * barGroupWidth + seriesIndex * (barWidth + 2) + 2;
      const barHeight = ((point.y - minY) / (maxY - minY)) * chartHeight;
      const y = padding + chartHeight - barHeight;

      ctx.fillRect(x, y, barWidth, barHeight);

      // Draw value labels
      ctx.fillStyle = '#374151';
      ctx.font = '12px sans-serif';
      ctx.textAlign = 'center';
      ctx.fillText(point.y.toString(), x + barWidth / 2, y - 5);

      // Draw x-axis labels
      if (seriesIndex === 0) {
        ctx.fillText(
          point.label || point.x.toString(),
          padding + index * barGroupWidth + barGroupWidth / 2,
          padding + chartHeight + 20
        );
      }
    });
  };

  const drawAreaChart = (
    ctx: CanvasRenderingContext2D,
    series: ChartSeries,
    padding: number,
    chartWidth: number,
    chartHeight: number,
    maxY: number,
    minY: number
  ) => {
    if (series.data.length === 0) return;

    // Create gradient
    const gradient = ctx.createLinearGradient(0, padding, 0, padding + chartHeight);
    gradient.addColorStop(0, `${series.color}40`);
    gradient.addColorStop(1, `${series.color}10`);

    ctx.fillStyle = gradient;
    ctx.strokeStyle = series.color;
    ctx.lineWidth = 2;

    ctx.beginPath();

    // Start from bottom left
    ctx.moveTo(padding, padding + chartHeight);

    series.data.forEach((point, index) => {
      const x = padding + (index * chartWidth) / (series.data.length - 1 || 1);
      const y = padding + chartHeight - ((point.y - minY) / (maxY - minY)) * chartHeight;
      ctx.lineTo(x, y);
    });

    // Close the path at bottom right
    ctx.lineTo(padding + chartWidth, padding + chartHeight);
    ctx.closePath();
    ctx.fill();

    // Draw the line on top
    ctx.beginPath();
    series.data.forEach((point, index) => {
      const x = padding + (index * chartWidth) / (series.data.length - 1 || 1);
      const y = padding + chartHeight - ((point.y - minY) / (maxY - minY)) * chartHeight;

      if (index === 0) {
        ctx.moveTo(x, y);
      } else {
        ctx.lineTo(x, y);
      }
    });
    ctx.stroke();
  };

  const drawLegend = (ctx: CanvasRenderingContext2D, seriesList: ChartSeries[], width: number, height: number) => {
    const legendY = height - 30;
    let legendX = width / 2 - (seriesList.length * 80) / 2;

    seriesList.forEach((series, index) => {
      // Draw legend color box
      ctx.fillStyle = series.color || getDefaultColor(index);
      ctx.fillRect(legendX, legendY, 12, 12);

      // Draw legend text
      ctx.fillStyle = '#374151';
      ctx.font = '12px sans-serif';
      ctx.textAlign = 'left';
      ctx.fillText(series.name, legendX + 18, legendY + 9);

      legendX += Math.max(80, ctx.measureText(series.name).width + 30);
    });
  };

  const getDefaultColor = (index: number): string => {
    const colors = [
      '#d97706', // orange
      '#0284c7', // blue
      '#16a34a', // green
      '#dc2626', // red
      '#7c3aed', // purple
      '#0891b2', // cyan
      '#ea580c', // orange variant
      '#059669'  // emerald
    ];
    return colors[index % colors.length];
  };

  return (
    <div className={`relative ${className}`} style={{ height: `${height}px` }}>
      <canvas
        ref={canvasRef}
        className="w-full h-full"
        style={{ height: `${height}px` }}
      />
    </div>
  );
};