import React, { useRef, useCallback, useState } from 'react';

const SIZE = 32;
const RADIUS = 12;
const STROKE = 3;
const START_ANGLE = 225;
const END_ANGLE = -45;
const RANGE = 270; // degrees

function polarToCart(cx, cy, r, deg) {
  const rad = (deg - 90) * Math.PI / 180;
  return { x: cx + r * Math.cos(rad), y: cy + r * Math.sin(rad) };
}

function describeArc(cx, cy, r, startDeg, endDeg) {
  const start = polarToCart(cx, cy, r, endDeg);
  const end = polarToCart(cx, cy, r, startDeg);
  const large = endDeg - startDeg <= 180 ? '0' : '1';
  return `M ${start.x} ${start.y} A ${r} ${r} 0 ${large} 0 ${end.x} ${end.y}`;
}

export default function Knob({ value, min, max, onChange, color = 'var(--accent)', label, unit, formatValue, modulated = false, liveValue }) {
  const ref = useRef(null);
  const dragRef = useRef(null);
  const inputRef = useRef(null);
  const [editing, setEditing] = useState(false);
  const [editText, setEditText] = useState('');

  // Use liveValue for visual display when being modulated, base value for interaction
  const displayNum = liveValue !== undefined ? liveValue : value;
  const clampedDisplay = Math.max(min, Math.min(max, displayNum));
  const norm = Math.max(0, Math.min(1, (clampedDisplay - min) / (max - min)));
  const angleDeg = START_ANGLE - norm * RANGE;

  const cx = SIZE / 2, cy = SIZE / 2;
  const trackPath = describeArc(cx, cy, RADIUS, END_ANGLE, START_ANGLE);
  const fillAngle = START_ANGLE - norm * RANGE;
  const fillPath = norm > 0.001 ? describeArc(cx, cy, RADIUS, fillAngle, START_ANGLE) : '';

  const dotPos = polarToCart(cx, cy, RADIUS - 4, angleDeg);

  // Also show base value indicator when modulated
  const baseNorm = Math.max(0, Math.min(1, (value - min) / (max - min)));
  const baseAngle = START_ANGLE - baseNorm * RANGE;
  const baseDotPos = polarToCart(cx, cy, RADIUS - 4, baseAngle);

  const displayVal = formatValue ? formatValue(displayNum) :
    displayNum >= 1000 ? `${(displayNum / 1000).toFixed(1)}k` :
    displayNum >= 100 ? Math.round(displayNum) :
    displayNum >= 1 ? displayNum.toFixed(1) :
    displayNum.toFixed(3).replace(/0+$/, '').replace(/\.$/, '');

  const handlePointerDown = useCallback((e) => {
    if (editing) return;
    e.preventDefault(); e.stopPropagation();
    dragRef.current = { startY: e.clientY, startValue: value };
    const handleMove = (me) => {
      const dy = dragRef.current.startY - me.clientY;
      const sensitivity = (max - min) / 200;
      let newVal = dragRef.current.startValue + dy * sensitivity;
      newVal = Math.max(min, Math.min(max, newVal));
      if (max - min > 10 && Number.isInteger(min) && Number.isInteger(max)) {
        newVal = Math.round(newVal);
      }
      onChange(newVal);
    };
    const handleUp = () => {
      window.removeEventListener('pointermove', handleMove);
      window.removeEventListener('pointerup', handleUp);
      dragRef.current = null;
    };
    window.addEventListener('pointermove', handleMove);
    window.addEventListener('pointerup', handleUp);
  }, [value, min, max, onChange, editing]);

  const handleWheel = useCallback((e) => {
    if (editing) return;
    e.preventDefault(); e.stopPropagation();
    const step = (max - min) / 100;
    const newVal = Math.max(min, Math.min(max, value - Math.sign(e.deltaY) * step));
    onChange(newVal);
  }, [value, min, max, onChange, editing]);

  // Double-click: open inline text input
  const handleDoubleClick = useCallback((e) => {
    e.preventDefault(); e.stopPropagation();
    setEditText(String(typeof displayVal === 'number' ? displayVal : value));
    setEditing(true);
    // Focus input after render
    setTimeout(() => inputRef.current?.focus(), 0);
  }, [value, displayVal]);

  const commitEdit = useCallback(() => {
    const parsed = parseFloat(editText);
    if (!isNaN(parsed)) {
      const clamped = Math.max(min, Math.min(max, parsed));
      onChange(clamped);
    }
    setEditing(false);
  }, [editText, min, max, onChange]);

  const handleInputKeyDown = useCallback((e) => {
    e.stopPropagation();
    if (e.key === 'Enter') {
      commitEdit();
    } else if (e.key === 'Escape') {
      setEditing(false);
    }
  }, [commitEdit]);

  const handleInputBlur = useCallback(() => {
    commitEdit();
  }, [commitEdit]);

  if (editing) {
    return (
      <div className="knob-container knob-editing" onWheel={(e) => e.stopPropagation()}>
        <input
          ref={inputRef}
          className="knob-input"
          type="text"
          value={editText}
          onChange={(e) => setEditText(e.target.value)}
          onKeyDown={handleInputKeyDown}
          onBlur={handleInputBlur}
          onPointerDown={(e) => e.stopPropagation()}
        />
      </div>
    );
  }

  return (
    <div className={`knob-container ${modulated ? 'knob-modulated' : ''}`} onWheel={handleWheel} onDoubleClick={handleDoubleClick}>
      <svg className="knob-svg" viewBox={`0 0 ${SIZE} ${SIZE}`}
        onPointerDown={handlePointerDown} ref={ref}>
        {/* Modulation glow ring */}
        {modulated && (
          <circle className="knob-mod-ring" cx={cx} cy={cy} r={RADIUS + 1} style={{ stroke: color }} />
        )}
        <path className="knob-track" d={trackPath} />
        {fillPath && <path className="knob-fill" d={fillPath} style={{ stroke: color }} />}
        {/* Ghost dot at base value position when modulated */}
        {liveValue !== undefined && (
          <circle className="knob-base-dot" cx={baseDotPos.x} cy={baseDotPos.y} r={1.5} />
        )}
        <circle className="knob-dot" cx={dotPos.x} cy={dotPos.y} r={2} />
      </svg>
    </div>
  );
}
