'use client';

import * as React from 'react';
import { cn } from '@/lib/utils/cn';
import type { AutomationLane as AutomationLaneType, AutomationPoint as AutomationPointType } from '@/types/automation';
import { AutomationPoint } from './AutomationPoint';

export interface AutomationLaneProps {
  lane: AutomationLaneType;
  duration: number; // Total timeline duration in seconds
  zoom: number; // Zoom factor
  currentTime?: number; // Playhead position
  onUpdateLane?: (updates: Partial<AutomationLaneType>) => void;
  onAddPoint?: (time: number, value: number) => void;
  onUpdatePoint?: (pointId: string, updates: Partial<AutomationPointType>) => void;
  onRemovePoint?: (pointId: string) => void;
  className?: string;
}

export function AutomationLane({
  lane,
  duration,
  zoom,
  currentTime = 0,
  onUpdateLane,
  onAddPoint,
  onUpdatePoint,
  onRemovePoint,
  className,
}: AutomationLaneProps) {
  const canvasRef = React.useRef<HTMLCanvasElement>(null);
  const containerRef = React.useRef<HTMLDivElement>(null);
  const [selectedPointId, setSelectedPointId] = React.useState<string | null>(null);
  const [isDraggingPoint, setIsDraggingPoint] = React.useState(false);

  // Convert time to X pixel position
  const timeToX = React.useCallback(
    (time: number): number => {
      if (!containerRef.current) return 0;
      const width = containerRef.current.clientWidth;
      return (time / duration) * width * zoom;
    },
    [duration, zoom]
  );

  // Convert value (0-1) to Y pixel position (inverted: 0 at bottom, 1 at top)
  const valueToY = React.useCallback(
    (value: number): number => {
      if (!containerRef.current) return 0;
      const height = lane.height;
      return height * (1 - value);
    },
    [lane.height]
  );

  // Convert X pixel position to time
  const xToTime = React.useCallback(
    (x: number): number => {
      if (!containerRef.current) return 0;
      const width = containerRef.current.clientWidth;
      return (x / (width * zoom)) * duration;
    },
    [duration, zoom]
  );

  // Convert Y pixel position to value (0-1)
  const yToValue = React.useCallback(
    (y: number): number => {
      const height = lane.height;
      return Math.max(0, Math.min(1, 1 - y / height));
    },
    [lane.height]
  );

  // Draw automation curve
  React.useEffect(() => {
    if (!canvasRef.current || !lane.visible) return;

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

    const dpr = window.devicePixelRatio || 1;
    const rect = canvas.getBoundingClientRect();

    canvas.width = rect.width * dpr;
    canvas.height = rect.height * dpr;
    ctx.scale(dpr, dpr);

    const width = rect.width;
    const height = rect.height;

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

    // Background
    ctx.fillStyle = getComputedStyle(canvas).getPropertyValue('--color-background') || 'rgb(15, 23, 42)';
    ctx.fillRect(0, 0, width, height);

    // Grid lines (horizontal value guides)
    ctx.strokeStyle = 'rgba(148, 163, 184, 0.1)';
    ctx.lineWidth = 1;
    for (let i = 0; i <= 4; i++) {
      const y = (height / 4) * i;
      ctx.beginPath();
      ctx.moveTo(0, y);
      ctx.lineTo(width, y);
      ctx.stroke();
    }

    // Draw automation curve
    if (lane.points.length > 0) {
      const color = lane.color || 'rgb(59, 130, 246)';
      ctx.strokeStyle = color;
      ctx.lineWidth = 2;
      ctx.beginPath();

      // Sort points by time
      const sortedPoints = [...lane.points].sort((a, b) => a.time - b.time);

      // Draw lines between points
      for (let i = 0; i < sortedPoints.length; i++) {
        const point = sortedPoints[i];
        const x = timeToX(point.time);
        const y = valueToY(point.value);

        if (i === 0) {
          // Start from left edge at first point's value
          ctx.moveTo(0, y);
          ctx.lineTo(x, y);
        } else {
          const prevPoint = sortedPoints[i - 1];
          const prevX = timeToX(prevPoint.time);
          const prevY = valueToY(prevPoint.value);

          if (point.curve === 'step') {
            // Step curve: horizontal then vertical
            ctx.lineTo(x, prevY);
            ctx.lineTo(x, y);
          } else {
            // Linear curve (bezier not implemented yet)
            ctx.lineTo(x, y);
          }
        }

        // Extend to right edge from last point
        if (i === sortedPoints.length - 1) {
          ctx.lineTo(width, y);
        }
      }

      ctx.stroke();

      // Fill area under curve
      ctx.globalAlpha = 0.2;
      ctx.fillStyle = color;
      ctx.lineTo(width, height);
      ctx.lineTo(0, height);
      ctx.closePath();
      ctx.fill();
      ctx.globalAlpha = 1.0;
    }

    // Draw playhead
    if (currentTime >= 0 && duration > 0) {
      const playheadX = timeToX(currentTime);
      if (playheadX >= 0 && playheadX <= width) {
        ctx.strokeStyle = 'rgba(239, 68, 68, 0.8)';
        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(playheadX, 0);
        ctx.lineTo(playheadX, height);
        ctx.stroke();
      }
    }
  }, [lane, duration, zoom, currentTime, timeToX, valueToY]);

  // Handle canvas click to add point
  const handleCanvasClick = React.useCallback(
    (e: React.MouseEvent<HTMLCanvasElement>) => {
      if (isDraggingPoint || !onAddPoint) return;

      const rect = e.currentTarget.getBoundingClientRect();
      const x = e.clientX - rect.left;
      const y = e.clientY - rect.top;

      const time = xToTime(x);
      const value = yToValue(y);

      onAddPoint(time, value);
    },
    [isDraggingPoint, onAddPoint, xToTime, yToValue]
  );

  // Handle point drag
  const handlePointDragStart = React.useCallback((pointId: string) => {
    setIsDraggingPoint(true);
    setSelectedPointId(pointId);
  }, []);

  const handlePointDrag = React.useCallback(
    (pointId: string, deltaX: number, deltaY: number) => {
      if (!containerRef.current || !onUpdatePoint) return;

      const point = lane.points.find((p) => p.id === pointId);
      if (!point) return;

      const rect = containerRef.current.getBoundingClientRect();
      const width = rect.width;

      // Calculate new time and value
      const timePerPixel = duration / (width * zoom);
      const valuePerPixel = 1 / lane.height;

      const newTime = Math.max(0, Math.min(duration, point.time + deltaX * timePerPixel));
      const newValue = Math.max(0, Math.min(1, point.value - deltaY * valuePerPixel));

      onUpdatePoint(pointId, { time: newTime, value: newValue });
    },
    [lane.points, lane.height, duration, zoom, onUpdatePoint]
  );

  const handlePointDragEnd = React.useCallback(() => {
    setIsDraggingPoint(false);
  }, []);

  // Handle point click (select)
  const handlePointClick = React.useCallback((pointId: string, event: React.MouseEvent) => {
    event.stopPropagation();
    setSelectedPointId(pointId);
  }, []);

  // Handle point double-click (delete)
  const handlePointDoubleClick = React.useCallback(
    (pointId: string) => {
      if (onRemovePoint) {
        onRemovePoint(pointId);
      }
    },
    [onRemovePoint]
  );

  // Handle keyboard delete
  React.useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if ((e.key === 'Delete' || e.key === 'Backspace') && selectedPointId && onRemovePoint) {
        e.preventDefault();
        onRemovePoint(selectedPointId);
        setSelectedPointId(null);
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [selectedPointId, onRemovePoint]);

  // Get current value at playhead (interpolated)
  const getCurrentValue = React.useCallback((): number | undefined => {
    if (lane.points.length === 0) return undefined;

    const sortedPoints = [...lane.points].sort((a, b) => a.time - b.time);

    // Find surrounding points
    let prevPoint = sortedPoints[0];
    let nextPoint = sortedPoints[sortedPoints.length - 1];

    for (let i = 0; i < sortedPoints.length - 1; i++) {
      if (sortedPoints[i].time <= currentTime && sortedPoints[i + 1].time >= currentTime) {
        prevPoint = sortedPoints[i];
        nextPoint = sortedPoints[i + 1];
        break;
      }
    }

    // Interpolate
    if (currentTime <= prevPoint.time) return prevPoint.value;
    if (currentTime >= nextPoint.time) return nextPoint.value;

    const timeDelta = nextPoint.time - prevPoint.time;
    const valueDelta = nextPoint.value - prevPoint.value;
    const progress = (currentTime - prevPoint.time) / timeDelta;

    return prevPoint.value + valueDelta * progress;
  }, [lane.points, currentTime]);

  if (!lane.visible) return null;

  return (
    <div
      ref={containerRef}
      className={cn('relative bg-background/30 overflow-hidden cursor-crosshair', className)}
      style={{ height: lane.height }}
    >
      <canvas
        ref={canvasRef}
        className="absolute inset-0 w-full h-full"
        onClick={handleCanvasClick}
      />

      {/* Automation points */}
      {lane.points.map((point) => (
        <AutomationPoint
          key={point.id}
          point={point}
          x={timeToX(point.time)}
          y={valueToY(point.value)}
          isSelected={selectedPointId === point.id}
          onDragStart={handlePointDragStart}
          onDrag={handlePointDrag}
          onDragEnd={handlePointDragEnd}
          onClick={handlePointClick}
          onDoubleClick={handlePointDoubleClick}
        />
      ))}
    </div>
  );
}
