'use client';

import { useMemo, useState, useRef, useCallback, useEffect } from 'react';
import { type ConversionResult } from '@/lib/units/units';
import { formatNumber, cn } from '@/lib/utils';

interface VisualComparisonProps {
  conversions: ConversionResult[];
  color: string;
  onValueChange?: (value: number, unit: string, dragging: boolean) => void;
}

export default function VisualComparison({
  conversions,
  color,
  onValueChange,
}: VisualComparisonProps) {
  const [draggingUnit, setDraggingUnit] = useState<string | null>(null);
  const [draggedPercentage, setDraggedPercentage] = useState<number | null>(null);
  const dragStartX = useRef<number>(0);
  const dragStartWidth = useRef<number>(0);
  const activeBarRef = useRef<HTMLDivElement | null>(null);
  const lastUpdateTime = useRef<number>(0);
  const baseConversionsRef = useRef<ConversionResult[]>([]);
  // Calculate percentages for visual bars using logarithmic scale
  const withPercentages = useMemo(() => {
    if (conversions.length === 0) return [];

    // Use base conversions for scale if we're dragging (keeps scale stable)
    const scaleSource = baseConversionsRef.current.length > 0 ? baseConversionsRef.current : conversions;

    // Get all values from the SCALE SOURCE (not current conversions)
    const values = scaleSource.map(c => Math.abs(c.value));
    const maxValue = Math.max(...values);
    const minValue = Math.min(...values.filter(v => v > 0));

    if (maxValue === 0 || !isFinite(maxValue)) {
      return conversions.map(c => ({ ...c, percentage: 0 }));
    }

    // Use logarithmic scale for better visualization
    return conversions.map(c => {
      const absValue = Math.abs(c.value);

      if (absValue === 0 || !isFinite(absValue)) {
        return { ...c, percentage: 2 }; // Show minimal bar
      }

      // Logarithmic scale
      const logValue = Math.log10(absValue);
      const logMax = Math.log10(maxValue);
      const logMin = minValue > 0 ? Math.log10(minValue) : logMax - 6; // 6 orders of magnitude range

      const logRange = logMax - logMin;

      let percentage: number;
      if (logRange === 0) {
        percentage = 100;
      } else {
        percentage = ((logValue - logMin) / logRange) * 100;
        // Ensure bars are visible - minimum 3%, maximum 100%
        percentage = Math.max(3, Math.min(100, percentage));
      }

      return {
        ...c,
        percentage,
      };
    });
  }, [conversions]);

  // Calculate value from percentage (reverse logarithmic scale)
  const calculateValueFromPercentage = useCallback((
    percentage: number,
    minValue: number,
    maxValue: number
  ): number => {
    const logMax = Math.log10(maxValue);
    const logMin = minValue > 0 ? Math.log10(minValue) : logMax - 6;
    const logRange = logMax - logMin;

    // Convert percentage back to log value
    const logValue = logMin + (percentage / 100) * logRange;
    // Convert log value back to actual value
    return Math.pow(10, logValue);
  }, []);

  // Mouse drag handlers
  const handleMouseDown = useCallback((e: React.MouseEvent, unit: string, currentPercentage: number, barElement: HTMLDivElement) => {
    if (!onValueChange) return;

    e.preventDefault();
    setDraggingUnit(unit);
    setDraggedPercentage(currentPercentage);
    dragStartX.current = e.clientX;
    dragStartWidth.current = currentPercentage;
    activeBarRef.current = barElement;
    // Save the current conversions as reference
    baseConversionsRef.current = [...conversions];
  }, [onValueChange, conversions]);

  const handleMouseMove = useCallback((e: MouseEvent) => {
    if (!draggingUnit || !activeBarRef.current || !onValueChange) return;

    // Throttle updates to every 16ms (~60fps)
    const now = Date.now();
    if (now - lastUpdateTime.current < 16) return;
    lastUpdateTime.current = now;

    const barWidth = activeBarRef.current.offsetWidth;
    const deltaX = e.clientX - dragStartX.current;
    const deltaPercentage = (deltaX / barWidth) * 100;

    let newPercentage = dragStartWidth.current + deltaPercentage;
    newPercentage = Math.max(3, Math.min(100, newPercentage));

    // Update visual percentage immediately
    setDraggedPercentage(newPercentage);

    // Use the base conversions (from when drag started) for scale calculation
    const baseConversions = baseConversionsRef.current.length > 0 ? baseConversionsRef.current : conversions;

    // Calculate min/max values for the scale from BASE conversions
    const values = baseConversions.map(c => Math.abs(c.value));
    const maxValue = Math.max(...values);
    const minValue = Math.min(...values.filter(v => v > 0));

    // Calculate new value from percentage
    const newValue = calculateValueFromPercentage(newPercentage, minValue, maxValue);

    onValueChange(newValue, draggingUnit, true); // true = currently dragging
  }, [draggingUnit, conversions, onValueChange, calculateValueFromPercentage]);

  const handleMouseUp = useCallback(() => {
    if (draggingUnit && onValueChange) {
      // Find the current value for the dragged unit
      const conversion = conversions.find(c => c.unit === draggingUnit);
      if (conversion) {
        onValueChange(conversion.value, draggingUnit, false); // false = drag ended
      }
    }
    setDraggingUnit(null);
    // Don't clear draggedPercentage yet - let it clear when conversions update
    activeBarRef.current = null;
    // baseConversionsRef cleared after conversions update
  }, [draggingUnit, conversions, onValueChange]);

  // Touch drag handlers
  const handleTouchStart = useCallback((e: React.TouchEvent, unit: string, currentPercentage: number, barElement: HTMLDivElement) => {
    if (!onValueChange) return;

    const touch = e.touches[0];
    setDraggingUnit(unit);
    setDraggedPercentage(currentPercentage);
    dragStartX.current = touch.clientX;
    dragStartWidth.current = currentPercentage;
    activeBarRef.current = barElement;
    // Save the current conversions as reference
    baseConversionsRef.current = [...conversions];
  }, [onValueChange, conversions]);

  const handleTouchMove = useCallback((e: TouchEvent) => {
    if (!draggingUnit || !activeBarRef.current || !onValueChange) return;

    // Throttle updates to every 16ms (~60fps)
    const now = Date.now();
    if (now - lastUpdateTime.current < 16) return;
    lastUpdateTime.current = now;

    e.preventDefault(); // Prevent scrolling while dragging
    const touch = e.touches[0];
    const barWidth = activeBarRef.current.offsetWidth;
    const deltaX = touch.clientX - dragStartX.current;
    const deltaPercentage = (deltaX / barWidth) * 100;

    let newPercentage = dragStartWidth.current + deltaPercentage;
    newPercentage = Math.max(3, Math.min(100, newPercentage));

    // Update visual percentage immediately
    setDraggedPercentage(newPercentage);

    // Use the base conversions (from when drag started) for scale calculation
    const baseConversions = baseConversionsRef.current.length > 0 ? baseConversionsRef.current : conversions;

    const values = baseConversions.map(c => Math.abs(c.value));
    const maxValue = Math.max(...values);
    const minValue = Math.min(...values.filter(v => v > 0));

    const newValue = calculateValueFromPercentage(newPercentage, minValue, maxValue);

    onValueChange(newValue, draggingUnit, true); // true = currently dragging
  }, [draggingUnit, conversions, onValueChange, calculateValueFromPercentage]);

  const handleTouchEnd = useCallback(() => {
    if (draggingUnit && onValueChange) {
      // Find the current value for the dragged unit
      const conversion = conversions.find(c => c.unit === draggingUnit);
      if (conversion) {
        onValueChange(conversion.value, draggingUnit, false); // false = drag ended
      }
    }
    setDraggingUnit(null);
    // Don't clear draggedPercentage yet - let it clear when conversions update
    activeBarRef.current = null;
    // baseConversionsRef cleared after conversions update
  }, [draggingUnit, conversions, onValueChange]);

  // Add/remove global event listeners for drag
  useEffect(() => {
    if (draggingUnit) {
      document.addEventListener('mousemove', handleMouseMove);
      document.addEventListener('mouseup', handleMouseUp);
      document.addEventListener('touchmove', handleTouchMove, { passive: false });
      document.addEventListener('touchend', handleTouchEnd);

      return () => {
        document.removeEventListener('mousemove', handleMouseMove);
        document.removeEventListener('mouseup', handleMouseUp);
        document.removeEventListener('touchmove', handleTouchMove);
        document.removeEventListener('touchend', handleTouchEnd);
      };
    }
  }, [draggingUnit, handleMouseMove, handleMouseUp, handleTouchMove, handleTouchEnd]);

  // Clear drag state when conversions update after drag ends
  useEffect(() => {
    if (!draggingUnit && draggedPercentage !== null) {
      // Drag has ended, conversions have updated, now clear visual state
      setDraggedPercentage(null);
      baseConversionsRef.current = [];
    }
  }, [conversions, draggingUnit, draggedPercentage]);

  if (conversions.length === 0) {
    return (
      <div className="text-center py-8 text-muted-foreground">
        Enter a value to see conversions
      </div>
    );
  }

  return (
    <div className="space-y-3">
      {withPercentages.map(item => {
        const isDragging = draggingUnit === item.unit;
        const isDraggable = !!onValueChange;
        // Use draggedPercentage if this bar is being dragged
        const displayPercentage = isDragging && draggedPercentage !== null ? draggedPercentage : item.percentage;

        return (
          <div key={item.unit} className="space-y-1.5">
            <div className="flex items-baseline justify-between gap-4">
              <span className="text-sm font-medium text-foreground min-w-0 flex-shrink">
                {item.unitInfo.plural}
              </span>
              <span className="text-lg font-bold tabular-nums flex-shrink-0">
                {formatNumber(item.value)}
                <span className="text-sm font-normal text-muted-foreground ml-1">
                  {item.unit}
                </span>
              </span>
            </div>
            {/* Progress bar */}
            <div
              className={cn(
                "w-full h-8 bg-muted rounded-lg overflow-hidden border border-border relative",
                "transition-all duration-200",
                isDraggable && "cursor-grab active:cursor-grabbing",
                isDragging && "ring-2 ring-ring ring-offset-2 ring-offset-background scale-105"
              )}
              onMouseDown={(e) => {
                if (isDraggable && e.currentTarget instanceof HTMLDivElement) {
                  handleMouseDown(e, item.unit, item.percentage, e.currentTarget);
                }
              }}
              onTouchStart={(e) => {
                if (isDraggable && e.currentTarget instanceof HTMLDivElement) {
                  handleTouchStart(e, item.unit, item.percentage, e.currentTarget);
                }
              }}
            >
              {/* Colored fill */}
              <div
                className={cn(
                  "absolute inset-y-0 left-0",
                  draggingUnit ? "transition-none" : "transition-all duration-500 ease-out"
                )}
                style={{
                  width: `${displayPercentage}%`,
                  backgroundColor: color,
                }}
              />
              {/* Percentage label overlay */}
              <div className="absolute inset-0 flex items-center px-3 text-xs font-bold pointer-events-none">
                <span className="text-foreground drop-shadow-sm">
                  {Math.round(displayPercentage)}%
                </span>
              </div>

              {/* Drag hint on hover */}
              {isDraggable && !isDragging && (
                <div className="absolute inset-0 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity bg-background/10 backdrop-blur-[1px]">
                  <span className="text-xs font-semibold text-foreground drop-shadow-md">
                    Drag to adjust
                  </span>
                </div>
              )}
            </div>
          </div>
        );
      })}
    </div>
  );
}
