import { useRef, useState, useEffect, useCallback } from 'react'
import { useStore } from '@nanostores/react'
import { mappingMode } from '../stores/mappingMode'

interface KnobProps {
  label: string
  value: number
  min: number
  max: number
  step: number
  unit?: string
  onChange: (value: number) => void
  formatValue?: (id: string, value: number) => string
  valueId?: string
  size?: number
  paramId?: string
  onMapClick?: (paramId: string, activeLFO: number) => void
  mappedLFOs?: number[]
}

export function Knob({
  label,
  value,
  min,
  max,
  step,
  unit,
  onChange,
  formatValue,
  valueId,
  size = 48,
  paramId,
  onMapClick,
  mappedLFOs = []
}: KnobProps) {
  const [isDragging, setIsDragging] = useState(false)
  const startYRef = useRef<number>(0)
  const startValueRef = useRef<number>(0)
  const mappingModeState = useStore(mappingMode)

  const displayValue = formatValue && valueId ? formatValue(valueId, value) : `${value}${unit || ''}`
  const isInMappingMode = mappingModeState.isActive && paramId
  const hasMappings = mappedLFOs.length > 0

  const normalizedValue = (value - min) / (max - min)
  const angle = -225 + normalizedValue * 270

  const handleMouseDown = (e: React.MouseEvent) => {
    if (isInMappingMode && paramId && mappingModeState.activeLFO !== null && onMapClick) {
      onMapClick(paramId, mappingModeState.activeLFO)
      e.preventDefault()
      return
    }

    setIsDragging(true)
    startYRef.current = e.clientY
    startValueRef.current = value
    e.preventDefault()
  }

  const handleMouseMove = useCallback((e: MouseEvent) => {
    if (!isDragging) return

    const deltaY = startYRef.current - e.clientY
    const range = max - min
    const sensitivity = range / 200
    const newValue = Math.max(min, Math.min(max, startValueRef.current + deltaY * sensitivity))

    const steppedValue = Math.round(newValue / step) * step
    onChange(steppedValue)
  }, [isDragging, max, min, step, onChange])

  const handleMouseUp = useCallback(() => {
    setIsDragging(false)
  }, [])

  useEffect(() => {
    if (isDragging) {
      window.addEventListener('mousemove', handleMouseMove)
      window.addEventListener('mouseup', handleMouseUp)
      return () => {
        window.removeEventListener('mousemove', handleMouseMove)
        window.removeEventListener('mouseup', handleMouseUp)
      }
    }
  }, [isDragging, handleMouseMove, handleMouseUp])

  return (
    <div className="relative flex flex-col items-center">
      <div
        className={`relative select-none ${isInMappingMode ? 'cursor-pointer' : 'cursor-ns-resize'}`}
        onMouseDown={handleMouseDown}
        style={{ width: size, height: size }}
      >
        <svg
          width={size}
          height={size}
          viewBox={`0 0 ${size} ${size}`}
        >
          <circle
            cx={size / 2}
            cy={size / 2}
            r={(size - 4) / 2}
            fill="none"
            stroke="white"
            strokeWidth="2"
            className={isInMappingMode ? 'animate-pulse' : ''}
          />

          <circle
            cx={size / 2}
            cy={size / 2}
            r={(size - 8) / 2}
            fill="black"
          />

          <line
            x1={size / 2 + Math.cos((angle * Math.PI) / 180) * ((size - 16) / 2)}
            y1={size / 2 + Math.sin((angle * Math.PI) / 180) * ((size - 16) / 2)}
            x2={size / 2 + Math.cos((angle * Math.PI) / 180) * ((size - 4) / 2)}
            y2={size / 2 + Math.sin((angle * Math.PI) / 180) * ((size - 4) / 2)}
            stroke="white"
            strokeWidth="2"
            strokeLinecap="square"
          />

          {hasMappings && (
            <circle
              cx={size / 2}
              cy={8}
              r={2}
              fill="white"
            />
          )}
        </svg>

        <div className="absolute inset-0 flex items-center justify-center pointer-events-none">
          <span className={`font-mono text-[9px] tracking-[0.15em] text-white ${isInMappingMode ? 'animate-pulse' : ''}`}>
            {isDragging ? displayValue : label.toUpperCase()}
          </span>
        </div>
      </div>
    </div>
  )
}
