/**
 * 채도·명도 영역 + Hue 슬라이더 + 스포이드 + RGB 입력 (TradingView 스타일)
 */
import React, { useCallback, useEffect, useRef, useState } from 'react';
import {
  hexToHsv,
  hexToRgb,
  hsvToHex,
  hsvToRgb,
  normalizeHex6,
  rgbToHex,
  rgbToHsv,
  svPanelBackground,
  HUE_SLIDER_BG,
  type Hsv,
} from '../utils/colorSpaceUtils';

export interface AdvancedColorPickerProps {
  hex6: string;
  onChange: (hex6: string) => void;
  className?: string;
}

function clamp01(n: number): number {
  return Math.max(0, Math.min(1, n));
}

function useHueDrag(onHue: (h: number) => void) {
  const dragging = useRef(false);

  const onPointerDown = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
    dragging.current = true;
    e.currentTarget.setPointerCapture(e.pointerId);
    const rect = e.currentTarget.getBoundingClientRect();
    const t = rect.width > 0 ? (e.clientX - rect.left) / rect.width : 0;
    onHue(clamp01(t) * 360);
  }, [onHue]);

  const onPointerMove = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
    if (!dragging.current) return;
    const rect = e.currentTarget.getBoundingClientRect();
    const t = rect.width > 0 ? (e.clientX - rect.left) / rect.width : 0;
    onHue(clamp01(t) * 360);
  }, [onHue]);

  const onPointerUp = useCallback((e: React.PointerEvent<HTMLDivElement>) => {
    dragging.current = false;
    try { e.currentTarget.releasePointerCapture(e.pointerId); } catch { /* noop */ }
  }, []);

  return { onPointerDown, onPointerMove, onPointerUp };
}

const AdvancedColorPicker: React.FC<AdvancedColorPickerProps> = ({
  hex6,
  onChange,
  className = '',
}) => {
  const [hsv, setHsv] = useState<Hsv>(() => hexToHsv(normalizeHex6(hex6)));
  const [rgb, setRgb] = useState(() => hexToRgb(normalizeHex6(hex6)));
  const [colorMode, setColorMode] = useState<'rgb' | 'hex'>('rgb');
  const skipSync = useRef(false);

  useEffect(() => {
    if (skipSync.current) {
      skipSync.current = false;
      return;
    }
    const h = hexToHsv(normalizeHex6(hex6));
    setHsv(h);
    setRgb(hexToRgb(normalizeHex6(hex6)));
  }, [hex6]);

  const emitHsv = useCallback((next: Hsv) => {
    const h = { h: next.h, s: clamp01(next.s), v: clamp01(next.v) };
    setHsv(h);
    const r = hsvToRgb(h);
    setRgb(r);
    skipSync.current = true;
    onChange(hsvToHex(h));
  }, [onChange]);

  const emitRgb = useCallback((r: number, g: number, b: number) => {
    const next = { r, g, b };
    setRgb(next);
    setHsv(rgbToHsv(next));
    skipSync.current = true;
    onChange(rgbToHex(r, g, b));
  }, [onChange]);

  const hueDrag = useHueDrag(h => emitHsv({ ...hsv, h }));

  const handleSvPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
    const el = e.currentTarget;
    const update = (cx: number, cy: number) => {
      const rect = el.getBoundingClientRect();
      const s = clamp01(rect.width > 0 ? (cx - rect.left) / rect.width : 0);
      const v = clamp01(rect.height > 0 ? 1 - (cy - rect.top) / rect.height : 0);
      emitHsv({ ...hsv, s, v });
    };
    update(e.clientX, e.clientY);
    const onMove = (ev: PointerEvent) => update(ev.clientX, ev.clientY);
    const onUp = () => {
      window.removeEventListener('pointermove', onMove);
      window.removeEventListener('pointerup', onUp);
    };
    window.addEventListener('pointermove', onMove);
    window.addEventListener('pointerup', onUp);
  };

  const pickEyedropper = async () => {
    const EyeDropperCtor = (window as Window & { EyeDropper?: new () => { open: () => Promise<{ sRGBHex: string }> } }).EyeDropper;
    if (!EyeDropperCtor) return;
    try {
      const result = await new EyeDropperCtor().open();
      if (result?.sRGBHex) {
        const hex = normalizeHex6(result.sRGBHex);
        emitHsv(hexToHsv(hex));
      }
    } catch {
      /* 사용자 취소 */
    }
  };

  const pointerX = `${hsv.s * 100}%`;
  const pointerY = `${(1 - hsv.v) * 100}%`;
  const hueLeft = `${(hsv.h / 360) * 100}%`;

  return (
    <div className={`acp-root ${className}`.trim()}>
      <div
        className="acp-sv-panel"
        style={{ background: svPanelBackground(hsv.h) }}
        onPointerDown={handleSvPointerDown}
        role="presentation"
      >
        <span
          className="acp-sv-pointer"
          style={{ left: pointerX, top: pointerY }}
          aria-hidden
        />
      </div>

      <div className="acp-controls-row">
        <button
          type="button"
          className="acp-eyedropper"
          title="스포이드"
          aria-label="스포이드로 색상 선택"
          onClick={() => void pickEyedropper()}
        >
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden>
            <path
              d="M20.71 5.63l-2.34-2.34a1 1 0 00-1.42 0l-3.12 3.12-1.93-1.91a1 1 0 00-1.41 0l-1.83 1.83a1 1 0 000 1.41l1.91 1.91-6.36 6.36a1 1 0 000 1.41l2.12 2.12a1 1 0 001.41 0l6.36-6.36 1.91 1.91a1 1 0 001.41 0l1.83-1.83a1 1 0 000-1.41l-1.92-1.9 3.12-3.12a1 1 0 000-1.42z"
              stroke="currentColor"
              strokeWidth="1.4"
              strokeLinejoin="round"
            />
          </svg>
        </button>
        <span
          className="acp-preview"
          style={{ background: normalizeHex6(hex6) }}
          aria-hidden
        />
        <div
          className="acp-hue-track"
          style={{ background: HUE_SLIDER_BG }}
          onPointerDown={hueDrag.onPointerDown}
          onPointerMove={hueDrag.onPointerMove}
          onPointerUp={hueDrag.onPointerUp}
          role="slider"
          aria-label="색상(Hue)"
          aria-valuemin={0}
          aria-valuemax={360}
          aria-valuenow={Math.round(hsv.h)}
        >
          <span className="acp-hue-thumb" style={{ left: hueLeft }} aria-hidden />
        </div>
      </div>

      <div className="acp-rgb-row">
        {colorMode === 'rgb' ? (
          <>
            {(['r', 'g', 'b'] as const).map(ch => (
              <label key={ch} className="acp-rgb-field">
                <input
                  type="number"
                  className="acp-rgb-input"
                  min={0}
                  max={255}
                  value={rgb[ch]}
                  onChange={e => {
                    const v = Number(e.target.value);
                    if (Number.isNaN(v)) return;
                    emitRgb(
                      ch === 'r' ? v : rgb.r,
                      ch === 'g' ? v : rgb.g,
                      ch === 'b' ? v : rgb.b,
                    );
                  }}
                />
                <span className="acp-rgb-label">{ch.toUpperCase()}</span>
              </label>
            ))}
          </>
        ) : (
          <label className="acp-rgb-field acp-hex-field">
            <input
              type="text"
              className="acp-rgb-input acp-hex-input"
              value={normalizeHex6(hex6).slice(1)}
              maxLength={6}
              onChange={e => {
                const raw = e.target.value.replace(/[^0-9A-Fa-f]/g, '').slice(0, 6);
                if (raw.length === 6) {
                  emitHsv(hexToHsv('#' + raw));
                }
              }}
            />
            <span className="acp-rgb-label">HEX</span>
          </label>
        )}
        <button
          type="button"
          className="acp-mode-toggle"
          title={colorMode === 'rgb' ? 'HEX 입력' : 'RGB 입력'}
          aria-label="색상 입력 방식 전환"
          onClick={() => setColorMode(m => (m === 'rgb' ? 'hex' : 'rgb'))}
        >
          ▾
        </button>
      </div>
    </div>
  );
};

export default AdvancedColorPicker;
