/**
 * 화면(탭/창) 공유 스트림 위에서 드래그로 영역 선택 → PNG File 반환
 */
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import {
  captureErrorMessage,
  clientRectToVideoPixels,
  cropVideoFrameToFile,
  requestDisplayCaptureStream,
  stopMediaStream,
  type ScreenCaptureRect,
} from '../utils/screenRegionCapture';

interface Props {
  onCapture: (file: File) => void;
  onCancel: () => void;
}

type Phase = 'starting' | 'ready' | 'selecting' | 'processing';

const MIN_DRAG_PX = 8;

const ScreenRegionCaptureOverlay: React.FC<Props> = ({ onCapture, onCancel }) => {
  const videoRef = useRef<HTMLVideoElement>(null);
  const streamRef = useRef<MediaStream | null>(null);
  const dragStartRef = useRef<{ x: number; y: number } | null>(null);
  const [phase, setPhase] = useState<Phase>('starting');
  const [selection, setSelection] = useState<ScreenCaptureRect | null>(null);
  const [error, setError] = useState<string | null>(null);

  const cleanup = useCallback(() => {
    stopMediaStream(streamRef.current);
    streamRef.current = null;
  }, []);

  useEffect(() => {
    let cancelled = false;

    (async () => {
      try {
        const stream = await requestDisplayCaptureStream();
        if (cancelled) {
          stopMediaStream(stream);
          return;
        }
        streamRef.current = stream;
        const video = videoRef.current;
        if (!video) {
          stopMediaStream(stream);
          onCancel();
          return;
        }
        video.srcObject = stream;
        video.muted = true;
        await video.play();
        if (cancelled) return;
        setPhase('ready');
      } catch (e) {
        if (!cancelled) {
          setError(captureErrorMessage(e));
          setTimeout(onCancel, 2200);
        }
      }
    })();

    return () => {
      cancelled = true;
      cleanup();
    };
  }, [cleanup, onCancel]);

  const finishCancel = useCallback(() => {
    cleanup();
    onCancel();
  }, [cleanup, onCancel]);

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') finishCancel();
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [finishCancel]);

  const normalizeRect = (x0: number, y0: number, x1: number, y1: number): ScreenCaptureRect => {
    const left = Math.min(x0, x1);
    const top = Math.min(y0, y1);
    return {
      left,
      top,
      width: Math.abs(x1 - x0),
      height: Math.abs(y1 - y0),
    };
  };

  const handlePointerDown = (e: React.PointerEvent) => {
    if (phase !== 'ready' && phase !== 'selecting') return;
    if (e.button !== 0) return;
    dragStartRef.current = { x: e.clientX, y: e.clientY };
    setSelection({ left: e.clientX, top: e.clientY, width: 0, height: 0 });
    setPhase('selecting');
    (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
  };

  const handlePointerMove = (e: React.PointerEvent) => {
    if (!dragStartRef.current) return;
    const start = dragStartRef.current;
    setSelection(normalizeRect(start.x, start.y, e.clientX, e.clientY));
  };

  const handlePointerUp = async (e: React.PointerEvent) => {
    if (!dragStartRef.current) return;
    const start = dragStartRef.current;
    dragStartRef.current = null;
    const clientRect = normalizeRect(start.x, start.y, e.clientX, e.clientY);
    if (clientRect.width < MIN_DRAG_PX || clientRect.height < MIN_DRAG_PX) {
      setSelection(null);
      setPhase('ready');
      return;
    }

    const video = videoRef.current;
    if (!video) {
      finishCancel();
      return;
    }

    setPhase('processing');
    try {
      const vidRect = clientRectToVideoPixels(clientRect, video);
      if (!vidRect) throw new Error('REGION_TOO_SMALL');
      const file = await cropVideoFrameToFile(video, vidRect);
      cleanup();
      onCapture(file);
    } catch (err) {
      setError(captureErrorMessage(err));
      setPhase('ready');
      setSelection(null);
    }
  };

  const hint =
    phase === 'starting'
      ? '화면 공유 준비 중…'
      : phase === 'processing'
        ? '캡처 처리 중…'
        : '캡처할 영역을 드래그하세요 · Esc 취소';

  return createPortal(
    <div className="screen-capture-overlay" role="dialog" aria-modal aria-label="화면 영역 캡처">
      <video ref={videoRef} className="screen-capture-video" playsInline />
      <div
        className="screen-capture-interaction"
        onPointerDown={handlePointerDown}
        onPointerMove={handlePointerMove}
        onPointerUp={e => void handlePointerUp(e)}
        onPointerCancel={() => {
          dragStartRef.current = null;
          setSelection(null);
          setPhase('ready');
        }}
      >
        {selection && selection.width > 0 && selection.height > 0 && (
          <div
            className="screen-capture-selection"
            style={{
              left: selection.left,
              top: selection.top,
              width: selection.width,
              height: selection.height,
            }}
          />
        )}
      </div>
      <div className="screen-capture-toolbar">
        <span className="screen-capture-hint">{error ?? hint}</span>
        <button type="button" className="screen-capture-cancel" onClick={finishCancel}>
          취소
        </button>
      </div>
    </div>,
    document.body,
  );
};

export default ScreenRegionCaptureOverlay;
