'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[];
  onValueChange?: (value: number, unit: string, dragging: boolean) => void;
}

export default function VisualComparison({ conversions, 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[]>([]);

  const withPercentages = useMemo(() => {
    if (conversions.length === 0) return [];
    const scaleSource = baseConversionsRef.current.length > 0 ? baseConversionsRef.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 }));
    }

    return conversions.map((c) => {
      const absValue = Math.abs(c.value);
      if (absValue === 0 || !isFinite(absValue)) return { ...c, percentage: 2 };
      const logValue = Math.log10(absValue);
      const logMax = Math.log10(maxValue);
      const logMin = minValue > 0 ? Math.log10(minValue) : logMax - 6;
      const logRange = logMax - logMin;
      const percentage =
        logRange === 0
          ? 100
          : Math.max(3, Math.min(100, ((logValue - logMin) / logRange) * 100));
      return { ...c, percentage };
    });
  }, [conversions]);

  const calculateValueFromPercentage = useCallback(
    (percentage: number, minValue: number, maxValue: number): number => {
      const logMax = Math.log10(maxValue);
      const logMin = minValue > 0 ? Math.log10(minValue) : logMax - 6;
      return Math.pow(10, logMin + (percentage / 100) * (logMax - logMin));
    },
    []
  );

  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;
      baseConversionsRef.current = [...conversions];
    },
    [onValueChange, conversions]
  );

  const handleMouseMove = useCallback(
    (e: MouseEvent) => {
      if (!draggingUnit || !activeBarRef.current || !onValueChange) return;
      const now = Date.now();
      if (now - lastUpdateTime.current < 16) return;
      lastUpdateTime.current = now;
      const deltaPercentage = ((e.clientX - dragStartX.current) / activeBarRef.current.offsetWidth) * 100;
      const newPercentage = Math.max(3, Math.min(100, dragStartWidth.current + deltaPercentage));
      setDraggedPercentage(newPercentage);
      const base = baseConversionsRef.current.length > 0 ? baseConversionsRef.current : conversions;
      const vals = base.map((c) => Math.abs(c.value));
      const newValue = calculateValueFromPercentage(newPercentage, Math.min(...vals.filter((v) => v > 0)), Math.max(...vals));
      onValueChange(newValue, draggingUnit, true);
    },
    [draggingUnit, conversions, onValueChange, calculateValueFromPercentage]
  );

  const handleMouseUp = useCallback(() => {
    if (draggingUnit && onValueChange) {
      const conversion = conversions.find((c) => c.unit === draggingUnit);
      if (conversion) onValueChange(conversion.value, draggingUnit, false);
    }
    setDraggingUnit(null);
    activeBarRef.current = null;
  }, [draggingUnit, conversions, onValueChange]);

  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;
      baseConversionsRef.current = [...conversions];
    },
    [onValueChange, conversions]
  );

  const handleTouchMove = useCallback(
    (e: TouchEvent) => {
      if (!draggingUnit || !activeBarRef.current || !onValueChange) return;
      const now = Date.now();
      if (now - lastUpdateTime.current < 16) return;
      lastUpdateTime.current = now;
      e.preventDefault();
      const touch = e.touches[0];
      const deltaPercentage = ((touch.clientX - dragStartX.current) / activeBarRef.current.offsetWidth) * 100;
      const newPercentage = Math.max(3, Math.min(100, dragStartWidth.current + deltaPercentage));
      setDraggedPercentage(newPercentage);
      const base = baseConversionsRef.current.length > 0 ? baseConversionsRef.current : conversions;
      const vals = base.map((c) => Math.abs(c.value));
      const newValue = calculateValueFromPercentage(newPercentage, Math.min(...vals.filter((v) => v > 0)), Math.max(...vals));
      onValueChange(newValue, draggingUnit, true);
    },
    [draggingUnit, conversions, onValueChange, calculateValueFromPercentage]
  );

  const handleTouchEnd = useCallback(() => {
    if (draggingUnit && onValueChange) {
      const conversion = conversions.find((c) => c.unit === draggingUnit);
      if (conversion) onValueChange(conversion.value, draggingUnit, false);
    }
    setDraggingUnit(null);
    activeBarRef.current = null;
  }, [draggingUnit, conversions, onValueChange]);

  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]);

  useEffect(() => {
    if (!draggingUnit && draggedPercentage !== null) {
      setDraggedPercentage(null);
      baseConversionsRef.current = [];
    }
  }, [conversions, draggingUnit, draggedPercentage]);

  if (conversions.length === 0) {
    return (
      <div className="py-10 text-center">
        <p className="text-xs text-muted-foreground/35 font-mono italic">Enter a value to see conversions</p>
      </div>
    );
  }

  return (
    <div className="space-y-2.5">
      {withPercentages.map((item) => {
        const isDragging = draggingUnit === item.unit;
        const isDraggable = !!onValueChange;
        const displayPercentage = isDragging && draggedPercentage !== null ? draggedPercentage : item.percentage;

        return (
          <div key={item.unit} className="space-y-1">
            <div className="flex items-baseline justify-between gap-3">
              <span className="text-[10px] text-muted-foreground/60 font-mono truncate">{item.unitInfo.plural}</span>
              <span className="text-xs font-bold tabular-nums font-mono shrink-0 text-foreground/85">
                {formatNumber(item.value)}
                <span className="text-[10px] font-normal text-muted-foreground/50 ml-1">{item.unit}</span>
              </span>
            </div>
            <div
              className={cn(
                'w-full h-5 rounded-md overflow-hidden relative',
                'bg-primary/6 border border-border/25',
                isDraggable && 'cursor-grab active:cursor-grabbing',
                isDragging && 'ring-1 ring-primary/40'
              )}
              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);
              }}
            >
              <div
                className={cn(
                  'absolute inset-y-0 left-0 rounded-sm bg-primary/65',
                  draggingUnit ? 'transition-none' : 'transition-all duration-500 ease-out'
                )}
                style={{ width: `${displayPercentage}%` }}
              />
              {isDraggable && !isDragging && (
                <div className="absolute inset-0 flex items-center justify-end px-2 opacity-0 hover:opacity-100 transition-opacity">
                  <span className="text-[9px] font-mono text-muted-foreground/40">drag</span>
                </div>
              )}
            </div>
          </div>
        );
      })}
    </div>
  );
}
