import { useCallback, useEffect, useRef, useState, type CSSProperties } from 'react';

type Props = {
  children: React.ReactNode;
};

const MIN = 160;
const MAX = 1200;

export function ResizableStage({ children }: Props) {
  const [size, setSize] = useState({ width: 520, height: 480 });
  const dragRef = useRef<{
    edge: 'e' | 's' | 'se';
    startX: number;
    startY: number;
    startW: number;
    startH: number;
  } | null>(null);

  const onPointerMove = useCallback((e: PointerEvent) => {
    const drag = dragRef.current;
    if (!drag) return;
    const dx = e.clientX - drag.startX;
    const dy = e.clientY - drag.startY;
    setSize((prev) => {
      let width = prev.width;
      let height = prev.height;
      if (drag.edge === 'e' || drag.edge === 'se') {
        width = clamp(drag.startW + dx, MIN, MAX);
      }
      if (drag.edge === 's' || drag.edge === 'se') {
        height = clamp(drag.startH + dy, MIN, MAX);
      }
      return { width, height };
    });
  }, []);

  const onPointerUp = useCallback(() => {
    dragRef.current = null;
    window.removeEventListener('pointermove', onPointerMove);
    window.removeEventListener('pointerup', onPointerUp);
  }, [onPointerMove]);

  const startDrag = (edge: 'e' | 's' | 'se') => (e: React.PointerEvent) => {
    e.preventDefault();
    dragRef.current = {
      edge,
      startX: e.clientX,
      startY: e.clientY,
      startW: size.width,
      startH: size.height,
    };
    window.addEventListener('pointermove', onPointerMove);
    window.addEventListener('pointerup', onPointerUp);
  };

  useEffect(() => () => onPointerUp(), [onPointerUp]);

  const stageStyle: CSSProperties = {
    width: size.width,
    height: size.height,
  };

  return (
    <div className="stage-wrap">
      <div className="stage-meta">
        {size.width} × {size.height}
      </div>
      <div className="stage" style={stageStyle}>
        <div className="stage-canvas">{children}</div>
        <button type="button" className="handle handle-e" aria-label="Resize width" onPointerDown={startDrag('e')} />
        <button type="button" className="handle handle-s" aria-label="Resize height" onPointerDown={startDrag('s')} />
        <button
          type="button"
          className="handle handle-se"
          aria-label="Resize both"
          onPointerDown={startDrag('se')}
        />
      </div>
    </div>
  );
}

function clamp(n: number, min: number, max: number) {
  return Math.min(max, Math.max(min, n));
}
