import {
  useRef,
  useEffect,
  useState,
  useCallback,
  useMemo,
  forwardRef,
  useImperativeHandle,
} from 'react';
import Hls from 'hls.js';
import { detectStreamType } from '../utils/streamUtils';
import { useOilDetection } from '../hooks/useOilDetection';
import OilDetectionOverlay from './OilDetectionOverlay';

interface CCTVPlayerProps {
  cameraNm: string;
  streamUrl: string | null;
  sttsCd: string;
  coordDc?: string | null;
  sourceNm?: string | null;
  cellIndex?: number;
  onClose?: () => void;
  oilDetectionEnabled?: boolean;
  vesselDetectionEnabled?: boolean;
  intrusionDetectionEnabled?: boolean;
}

export interface CCTVPlayerHandle {
  capture: () => void;
}

type PlayerState = 'loading' | 'playing' | 'error' | 'offline' | 'no-url';

/** 외부 HLS URL을 백엔드 프록시 경유 URL로 변환 */
function toProxyUrl(url: string): string {
  if (url.startsWith('http://') || url.startsWith('https://')) {
    return `/api/aerial/cctv/stream-proxy?url=${encodeURIComponent(url)}`;
  }
  return url;
}

export const CCTVPlayer = forwardRef<CCTVPlayerHandle, CCTVPlayerProps>(
  (
    {
      cameraNm,
      streamUrl,
      sttsCd,
      cellIndex = 0,
      onClose,
      oilDetectionEnabled = false,
      vesselDetectionEnabled = false,
      intrusionDetectionEnabled = false,
    },
    ref,
  ) => {
    const videoRef = useRef<HTMLVideoElement>(null);
    const containerRef = useRef<HTMLDivElement>(null);
    const hlsRef = useRef<Hls | null>(null);
    const [hlsPlayerState, setHlsPlayerState] = useState<'loading' | 'playing' | 'error'>(
      'loading',
    );
    const [retryKey, setRetryKey] = useState(0);

    /** 원본 URL 기반으로 타입 감지, 재생은 프록시 URL 사용 */
    const proxiedUrl = useMemo(() => (streamUrl ? toProxyUrl(streamUrl) : null), [streamUrl]);

    /** props 기반으로 상태를 동기적으로 파생 */
    const isOffline = sttsCd === 'OFFLINE' || sttsCd === 'MAINT';
    const hasNoUrl = !isOffline && (!streamUrl || !proxiedUrl);
    const streamType = useMemo(
      () => (streamUrl && !isOffline ? detectStreamType(streamUrl) : null),
      [streamUrl, isOffline],
    );

    const playerState: PlayerState = isOffline
      ? 'offline'
      : hasNoUrl
        ? 'no-url'
        : streamType === 'mjpeg' || streamType === 'iframe'
          ? 'playing'
          : hlsPlayerState;

    const {
      result: oilResult,
      isAnalyzing: oilAnalyzing,
      error: oilError,
    } = useOilDetection({
      videoRef,
      enabled:
        oilDetectionEnabled &&
        playerState === 'playing' &&
        (streamType === 'hls' || streamType === 'mp4'),
    });

    useImperativeHandle(
      ref,
      () => ({
        capture: () => {
          const container = containerRef.current;
          if (!container) return;

          const w = container.clientWidth;
          const h = container.clientHeight;
          const canvas = document.createElement('canvas');
          canvas.width = w * 2;
          canvas.height = h * 2;
          const ctx = canvas.getContext('2d');
          if (!ctx) return;
          ctx.scale(2, 2);

          // 1) video frame
          const video = videoRef.current;
          if (video && video.readyState >= 2) {
            ctx.drawImage(video, 0, 0, w, h);
          }

          // 2) oil detection overlay
          const overlayCanvas = container.querySelector<HTMLCanvasElement>('canvas');
          if (overlayCanvas) {
            ctx.drawImage(overlayCanvas, 0, 0, w, h);
          }

          // 3) OSD: camera name + timestamp
          ctx.fillStyle = 'rgba(0,0,0,0.7)';
          ctx.fillRect(8, 8, ctx.measureText(cameraNm).width + 20, 22);
          ctx.font = 'bold 12px sans-serif';
          ctx.fillStyle = '#ffffff';
          ctx.fillText(cameraNm, 18, 23);

          const ts = new Date().toLocaleString('ko-KR');
          ctx.font = '10px monospace';
          ctx.fillStyle = 'rgba(0,0,0,0.7)';
          const tsW = ctx.measureText(ts).width + 16;
          ctx.fillRect(8, h - 26, tsW, 20);
          ctx.fillStyle = '#a0aec0';
          ctx.fillText(ts, 16, h - 12);

          // 4) oil detection info
          if (oilResult && oilResult.regions.length > 0) {
            const areaText =
              oilResult.totalAreaM2 >= 1000
                ? `오일 감지: ${(oilResult.totalAreaM2 / 1_000_000).toFixed(1)} km² (${oilResult.totalPercentage.toFixed(1)}%)`
                : `오일 감지: ~${Math.round(oilResult.totalAreaM2)} m² (${oilResult.totalPercentage.toFixed(1)}%)`;
            ctx.font = 'bold 11px sans-serif';
            const atW = ctx.measureText(areaText).width + 16;
            ctx.fillStyle = 'rgba(239,68,68,0.25)';
            ctx.fillRect(8, h - 48, atW, 18);
            ctx.fillStyle = '#f87171';
            ctx.fillText(areaText, 16, h - 34);
          }

          // download
          const link = document.createElement('a');
          link.download = `CCTV_${cameraNm}_${new Date().toISOString().slice(0, 19).replace(/:/g, '')}.png`;
          link.href = canvas.toDataURL('image/png');
          link.click();
        },
      }),
      [cameraNm, oilResult],
    );

    const destroyHls = useCallback(() => {
      if (hlsRef.current) {
        hlsRef.current.destroy();
        hlsRef.current = null;
      }
    }, []);

    useEffect(() => {
      if (isOffline || hasNoUrl || !streamUrl || !proxiedUrl) {
        destroyHls();
        return;
      }

      const type = detectStreamType(streamUrl);
      queueMicrotask(() => setHlsPlayerState('loading'));

      if (type === 'hls') {
        const video = videoRef.current;
        if (!video) return;

        if (Hls.isSupported()) {
          destroyHls();
          const hls = new Hls({
            enableWorker: true,
            lowLatencyMode: true,
            maxBufferLength: 10,
            maxMaxBufferLength: 30,
          });
          hlsRef.current = hls;
          hls.loadSource(proxiedUrl);
          hls.attachMedia(video);
          hls.on(Hls.Events.MANIFEST_PARSED, () => {
            setHlsPlayerState('playing');
            video.play().catch(() => {});
          });
          hls.on(Hls.Events.ERROR, (_event, data) => {
            if (data.fatal) {
              setHlsPlayerState('error');
              if (data.type === Hls.ErrorTypes.NETWORK_ERROR) {
                setTimeout(() => hls.startLoad(), 3000);
              }
            }
          });
          return () => destroyHls();
        }

        // Safari 네이티브 HLS (프록시 경유)
        if (video.canPlayType('application/vnd.apple.mpegurl')) {
          video.src = proxiedUrl;
          const onLoaded = () => setHlsPlayerState('playing');
          const onError = () => setHlsPlayerState('error');
          video.addEventListener('loadeddata', onLoaded);
          video.addEventListener('error', onError);
          video.play().catch(() => {});
          return () => {
            video.removeEventListener('loadeddata', onLoaded);
            video.removeEventListener('error', onError);
          };
        }

        queueMicrotask(() => setHlsPlayerState('error'));
        return;
      }

      if (type === 'mp4') {
        const video = videoRef.current;
        if (!video) return;
        video.src = proxiedUrl;
        const onLoaded = () => setHlsPlayerState('playing');
        const onError = () => setHlsPlayerState('error');
        video.addEventListener('loadeddata', onLoaded);
        video.addEventListener('error', onError);
        video.play().catch(() => {});
        return () => {
          video.removeEventListener('loadeddata', onLoaded);
          video.removeEventListener('error', onError);
        };
      }

      if (type === 'mjpeg' || type === 'iframe') {
        return;
      }

      queueMicrotask(() => setHlsPlayerState('error'));
      return () => destroyHls();
    }, [streamUrl, proxiedUrl, isOffline, hasNoUrl, destroyHls, retryKey]);

    // 오프라인
    if (playerState === 'offline') {
      return (
        <div className="absolute inset-0 flex flex-col items-center justify-center bg-bg-base">
          <div className="text-2xl opacity-30 mb-2">📹</div>
          <div className="text-label-2 font-korean text-fg-disabled opacity-70">
            {sttsCd === 'MAINT' ? '점검중' : '오프라인'}
          </div>
          <div className="text-caption font-korean text-fg-disabled opacity-40 mt-1">
            {cameraNm}
          </div>
        </div>
      );
    }

    // URL 미설정
    if (playerState === 'no-url') {
      return (
        <div className="absolute inset-0 flex flex-col items-center justify-center bg-bg-base">
          <div className="text-2xl opacity-20 mb-2">📹</div>
          <div className="text-caption font-korean text-fg-disabled opacity-50">
            스트림 URL 미설정
          </div>
          <div className="text-caption font-korean text-fg-disabled opacity-30 mt-1">
            {cameraNm}
          </div>
        </div>
      );
    }

    // 에러
    if (playerState === 'error') {
      return (
        <div className="absolute inset-0 flex flex-col items-center justify-center bg-bg-base">
          <div className="text-2xl opacity-30 mb-2">⚠️</div>
          <div className="text-caption font-korean text-color-danger opacity-70">연결 실패</div>
          <div className="text-caption font-korean text-fg-disabled opacity-40 mt-1">
            {cameraNm}
          </div>
          <button
            onClick={() => setRetryKey((k) => k + 1)}
            className="mt-2 px-2.5 py-1 rounded text-caption font-korean bg-bg-card border border-stroke text-fg-sub cursor-pointer hover:bg-bg-surface-hover transition-colors"
          >
            재시도
          </button>
        </div>
      );
    }

    return (
      <div ref={containerRef} className="absolute inset-0">
        {/* 로딩 오버레이 */}
        {playerState === 'loading' && (
          <div className="absolute inset-0 flex flex-col items-center justify-center bg-bg-base z-10">
            <div className="text-lg opacity-40 animate-pulse mb-2">📹</div>
            <div className="text-caption font-korean text-fg-disabled opacity-50">연결 중...</div>
          </div>
        )}

        {/* HLS / MP4 */}
        {(streamType === 'hls' || streamType === 'mp4') && (
          <video
            ref={videoRef}
            key={`video-${cellIndex}-${retryKey}`}
            className="absolute inset-0 w-full h-full object-cover"
            muted
            autoPlay
            playsInline
            loop={streamType === 'mp4'}
          />
        )}

        {/* 오일 감지 오버레이 */}
        {oilDetectionEnabled && (
          <OilDetectionOverlay result={oilResult} isAnalyzing={oilAnalyzing} error={oilError} />
        )}

        {/* MJPEG */}
        {streamType === 'mjpeg' && proxiedUrl && (
          <img
            src={proxiedUrl}
            alt={cameraNm}
            className="absolute inset-0 w-full h-full object-cover"
            onError={() => setHlsPlayerState('error')}
          />
        )}

        {/* iframe (원본 URL 사용 — iframe은 자체 CORS) */}
        {streamType === 'iframe' && streamUrl && (
          <iframe
            src={streamUrl}
            title={cameraNm}
            className="absolute inset-0 w-full h-full border-none"
            allow="autoplay; encrypted-media"
            onError={() => setHlsPlayerState('error')}
          />
        )}

        {/* 안전관리 감지 상태 배지 */}
        {(vesselDetectionEnabled || intrusionDetectionEnabled) && (
          <div className="absolute top-2 right-2 flex flex-col gap-1 z-20">
            {vesselDetectionEnabled && (
              <div
                className="flex items-center gap-1 px-1.5 py-0.5 rounded text-caption font-bold"
                style={{
                  background: 'color-mix(in srgb, var(--color-info) 30%, transparent)',
                  color: 'var(--color-info)',
                }}
              >
                🚢 선박 출입 감지 중
              </div>
            )}
            {intrusionDetectionEnabled && (
              <div
                className="flex items-center gap-1 px-1.5 py-0.5 rounded text-caption font-bold"
                style={{
                  background: 'color-mix(in srgb, var(--color-warning) 30%, transparent)',
                  color: 'var(--color-warning)',
                }}
              >
                🚨 침입 감지 중
              </div>
            )}
          </div>
        )}

        {/* OSD 오버레이 */}
        <div className="absolute top-2 left-2 flex items-center gap-1.5 z-20">
          <span className="text-caption font-bold px-1.5 py-0.5 rounded bg-black/70 text-white">
            {cameraNm}
          </span>
          {sttsCd === 'LIVE' && (
            <span
              className="text-caption font-bold px-1 py-0.5 rounded text-color-danger"
              style={{ background: 'color-mix(in srgb, var(--color-danger) 30%, transparent)' }}
            >
              ● REC
            </span>
          )}
        </div>

        {/* 닫기 (지도로 돌아가기) */}
        {onClose && (
          <button
            onClick={onClose}
            className="absolute top-2 right-2 w-7 h-7 flex items-center justify-center rounded bg-black/60 hover:bg-black/80 text-white/70 hover:text-white cursor-pointer transition-colors z-20"
            title="지도로 돌아가기"
          >
            <svg
              width="14"
              height="14"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              strokeWidth="2.5"
              strokeLinecap="round"
              strokeLinejoin="round"
            >
              <path d="M19 12H5" />
              <path d="M12 19l-7-7 7-7" />
            </svg>
          </button>
        )}
        {/* <div className="absolute bottom-2 left-2 text-caption font-mono px-1.5 py-0.5 rounded text-fg-disabled bg-black/70 z-20">
          {coordDc ?? ''}
          {sourceNm ? ` · ${sourceNm}` : ''}
        </div> */}
      </div>
    );
  },
);

CCTVPlayer.displayName = 'CCTVPlayer';
