import React, { useCallback, useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import {
  bindPaletteDragOverlayElement,
  notifyPaletteDragCancel,
  notifyPaletteDragEnd,
  notifyPaletteDragMove,
  registerPaletteDragOverlay,
  subscribePaletteDrag,
  type PaletteDragOverlaySession,
} from '../../utils/paletteDragSession';
import { clientXYFromReact } from '../../utils/pointerDrag';

/**
 * pointer/touch 드래그 overlay (sessionRef 로 stale closure 방지, window touch 백업과 연동)
 */
export default function PaletteDragOverlay() {
  const [session, setSession] = useState<PaletteDragOverlaySession | null>(null);
  const sessionRef = useRef<PaletteDragOverlaySession | null>(null);
  const labelRef = useRef<HTMLDivElement | null>(null);

  sessionRef.current = session;

  useEffect(() => {
    registerPaletteDragOverlay({
      mount: next => {
        sessionRef.current = next;
        setSession(next);
      },
      unmount: () => {
        sessionRef.current = null;
        setSession(null);
        bindPaletteDragOverlayElement(null);
      },
      bindElement: () => { /* ref callback 에서 처리 */ },
    });
    return () => registerPaletteDragOverlay(null);
  }, []);

  useEffect(() => {
    return subscribePaletteDrag(ev => {
      if (ev.phase !== 'move' && ev.phase !== 'start') return;
      const label = labelRef.current;
      if (!label) return;
      label.style.left = `${ev.x}px`;
      label.style.top = `${ev.y}px`;
    });
  }, []);

  const overlayRefCallback = useCallback((el: HTMLDivElement | null) => {
    bindPaletteDragOverlayElement(el);
    const s = sessionRef.current;
    if (el && s) {
      const label = labelRef.current;
      if (label) {
        label.style.left = `${s.x}px`;
        label.style.top = `${s.y}px`;
      }
    }
  }, []);

  const onPointerMove = useCallback((e: React.PointerEvent) => {
    const s = sessionRef.current;
    if (!s || e.pointerId !== s.pointerId) return;
    e.preventDefault();
    notifyPaletteDragMove(e.clientX, e.clientY);
  }, []);

  const onPointerUp = useCallback((e: React.PointerEvent) => {
    const s = sessionRef.current;
    if (!s || e.pointerId !== s.pointerId) return;
    e.preventDefault();
    notifyPaletteDragEnd(e.clientX, e.clientY);
  }, []);

  const onPointerCancel = useCallback((e: React.PointerEvent) => {
    const s = sessionRef.current;
    if (!s || e.pointerId !== s.pointerId) return;
    e.preventDefault();
    notifyPaletteDragCancel(e.clientX, e.clientY);
  }, []);

  const onTouchMove = useCallback((e: React.TouchEvent) => {
    const s = sessionRef.current;
    if (!s || e.touches.length !== 1) return;
    e.preventDefault();
    const { x, y } = clientXYFromReact(e);
    notifyPaletteDragMove(x, y);
  }, []);

  const onTouchEnd = useCallback((e: React.TouchEvent) => {
    const s = sessionRef.current;
    if (!s) return;
    const { x, y } = clientXYFromReact(e);
    e.preventDefault();
    notifyPaletteDragEnd(x, y);
  }, []);

  const onTouchCancel = useCallback((e: React.TouchEvent) => {
    const s = sessionRef.current;
    if (!s) return;
    const { x, y } = clientXYFromReact(e);
    e.preventDefault();
    notifyPaletteDragCancel(x, y);
  }, []);

  if (!session) return null;

  return createPortal(
    <div
      ref={overlayRefCallback}
      className="se-palette-drag-overlay"
      onPointerMove={onPointerMove}
      onPointerUp={onPointerUp}
      onPointerCancel={onPointerCancel}
      onTouchMove={onTouchMove}
      onTouchEnd={onTouchEnd}
      onTouchCancel={onTouchCancel}
    >
      <div
        ref={labelRef}
        className="se-palette-drag-overlay-label"
        style={{ left: session.x, top: session.y }}
      >
        {session.payload.label}
      </div>
    </div>,
    document.body,
  );
}
