import { useCallback, useEffect, useMemo, useRef, useState, type PointerEvent as ReactPointerEvent } from 'react';
import { useTrackPlaybackStore, TRACK_PLAYBACK_SPEED_OPTIONS } from '../../features/trackReplay/stores/trackPlaybackStore';
import { useTrackQueryStore } from '../../features/trackReplay/stores/trackQueryStore';

function formatDateTime(ms: number): string {
  if (!Number.isFinite(ms) || ms <= 0) return '--';
  const date = new Date(ms);
  const pad = (value: number) => String(value).padStart(2, '0');
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(
    date.getMinutes(),
  )}:${pad(date.getSeconds())}`;
}

export function GlobalTrackReplayPanel() {
  const PANEL_WIDTH = 420;
  const PANEL_MARGIN = 12;
  const PANEL_DEFAULT_TOP = 16;
  const PANEL_RIGHT_RESERVED = 520;

  const panelRef = useRef<HTMLDivElement | null>(null);
  const dragRef = useRef<{ pointerId: number; startX: number; startY: number; originX: number; originY: number } | null>(
    null,
  );
  const [isDragging, setIsDragging] = useState(false);

  const clampPosition = useCallback(
    (x: number, y: number) => {
      if (typeof window === 'undefined') return { x, y };
      const viewportWidth = window.innerWidth;
      const viewportHeight = window.innerHeight;
      const panelHeight = panelRef.current?.offsetHeight ?? 360;
      return {
        x: Math.min(Math.max(PANEL_MARGIN, x), Math.max(PANEL_MARGIN, viewportWidth - PANEL_WIDTH - PANEL_MARGIN)),
        y: Math.min(Math.max(PANEL_MARGIN, y), Math.max(PANEL_MARGIN, viewportHeight - panelHeight - PANEL_MARGIN)),
      };
    },
    [PANEL_MARGIN, PANEL_WIDTH],
  );

  const [position, setPosition] = useState(() => {
    if (typeof window === 'undefined') {
      return { x: PANEL_MARGIN, y: PANEL_DEFAULT_TOP };
    }
    return {
      x: Math.max(PANEL_MARGIN, window.innerWidth - PANEL_WIDTH - PANEL_RIGHT_RESERVED),
      y: PANEL_DEFAULT_TOP,
    };
  });

  const tracks = useTrackQueryStore((state) => state.tracks);
  const isLoading = useTrackQueryStore((state) => state.isLoading);
  const error = useTrackQueryStore((state) => state.error);
  const showPoints = useTrackQueryStore((state) => state.showPoints);
  const showVirtualShip = useTrackQueryStore((state) => state.showVirtualShip);
  const showLabels = useTrackQueryStore((state) => state.showLabels);
  const showTrail = useTrackQueryStore((state) => state.showTrail);
  const hideLiveShips = useTrackQueryStore((state) => state.hideLiveShips);
  const setShowPoints = useTrackQueryStore((state) => state.setShowPoints);
  const setShowVirtualShip = useTrackQueryStore((state) => state.setShowVirtualShip);
  const setShowLabels = useTrackQueryStore((state) => state.setShowLabels);
  const setShowTrail = useTrackQueryStore((state) => state.setShowTrail);
  const setHideLiveShips = useTrackQueryStore((state) => state.setHideLiveShips);
  const closeTrackQuery = useTrackQueryStore((state) => state.closeQuery);

  const isPlaying = useTrackPlaybackStore((state) => state.isPlaying);
  const currentTime = useTrackPlaybackStore((state) => state.currentTime);
  const startTime = useTrackPlaybackStore((state) => state.startTime);
  const endTime = useTrackPlaybackStore((state) => state.endTime);
  const playbackSpeed = useTrackPlaybackStore((state) => state.playbackSpeed);
  const loop = useTrackPlaybackStore((state) => state.loop);
  const play = useTrackPlaybackStore((state) => state.play);
  const pause = useTrackPlaybackStore((state) => state.pause);
  const stop = useTrackPlaybackStore((state) => state.stop);
  const setCurrentTime = useTrackPlaybackStore((state) => state.setCurrentTime);
  const setPlaybackSpeed = useTrackPlaybackStore((state) => state.setPlaybackSpeed);
  const toggleLoop = useTrackPlaybackStore((state) => state.toggleLoop);

  const progress = useMemo(() => {
    if (endTime <= startTime) return 0;
    return ((currentTime - startTime) / (endTime - startTime)) * 100;
  }, [startTime, endTime, currentTime]);
  const isVisible = isLoading || tracks.length > 0 || !!error;

  useEffect(() => {
    if (!isVisible) return;
    if (typeof window === 'undefined') return;
    const onResize = () => {
      setPosition((prev) => clampPosition(prev.x, prev.y));
    };
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, [clampPosition, isVisible]);

  useEffect(() => {
    if (!isVisible) return;
    const onPointerMove = (event: PointerEvent) => {
      const drag = dragRef.current;
      if (!drag || drag.pointerId !== event.pointerId) return;
      setPosition(() => {
        const nextX = drag.originX + (event.clientX - drag.startX);
        const nextY = drag.originY + (event.clientY - drag.startY);
        return clampPosition(nextX, nextY);
      });
    };

    const stopDrag = (event: PointerEvent) => {
      const drag = dragRef.current;
      if (!drag || drag.pointerId !== event.pointerId) return;
      dragRef.current = null;
      setIsDragging(false);
    };

    window.addEventListener('pointermove', onPointerMove);
    window.addEventListener('pointerup', stopDrag);
    window.addEventListener('pointercancel', stopDrag);

    return () => {
      window.removeEventListener('pointermove', onPointerMove);
      window.removeEventListener('pointerup', stopDrag);
      window.removeEventListener('pointercancel', stopDrag);
    };
  }, [clampPosition, isVisible]);

  const handleHeaderPointerDown = useCallback(
    (event: ReactPointerEvent<HTMLDivElement>) => {
      if (event.button !== 0) return;
      dragRef.current = {
        pointerId: event.pointerId,
        startX: event.clientX,
        startY: event.clientY,
        originX: position.x,
        originY: position.y,
      };
      setIsDragging(true);
      try {
        event.currentTarget.setPointerCapture(event.pointerId);
      } catch {
        // ignore
      }
    },
    [position.x, position.y],
  );

  if (!isVisible) return null;

  return (
    <div
      ref={panelRef}
      style={{
        position: 'absolute',
        left: position.x,
        top: position.y,
        width: PANEL_WIDTH,
        background: 'rgba(15,23,42,0.94)',
        border: '1px solid rgba(148,163,184,0.35)',
        borderRadius: 12,
        padding: 12,
        color: '#e2e8f0',
        zIndex: 40,
        backdropFilter: 'blur(8px)',
        boxShadow: '0 8px 24px rgba(2,6,23,0.45)',
      }}
    >
      <div
        onPointerDown={handleHeaderPointerDown}
        style={{
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'space-between',
          marginBottom: 8,
          cursor: isDragging ? 'grabbing' : 'grab',
          userSelect: 'none',
          touchAction: 'none',
        }}
      >
        <strong style={{ fontSize: 13 }}>Track Replay</strong>
        <button
          type="button"
          onClick={() => closeTrackQuery()}
          onPointerDown={(event) => event.stopPropagation()}
          style={{
            fontSize: 11,
            padding: '4px 8px',
            borderRadius: 6,
            border: '1px solid rgba(148,163,184,0.5)',
            background: 'rgba(30,41,59,0.7)',
            color: '#e2e8f0',
            cursor: 'pointer',
          }}
        >
          닫기
        </button>
      </div>

      {error ? (
        <div style={{ marginBottom: 8, color: '#fca5a5', fontSize: 12 }}>{error}</div>
      ) : null}

      {isLoading ? <div style={{ marginBottom: 8, fontSize: 12 }}>항적 조회 중...</div> : null}

      <div style={{ fontSize: 11, color: '#93c5fd', marginBottom: 8 }}>
        선박 {tracks.length}척 · {formatDateTime(startTime)} ~ {formatDateTime(endTime)}
      </div>

      <div style={{ display: 'flex', gap: 8, marginBottom: 10 }}>
        <button
          type="button"
          onClick={() => (isPlaying ? pause() : play())}
          disabled={tracks.length === 0}
          style={{
            padding: '6px 10px',
            borderRadius: 6,
            border: '1px solid rgba(148,163,184,0.45)',
            background: 'rgba(30,41,59,0.8)',
            color: '#e2e8f0',
            cursor: 'pointer',
          }}
        >
          {isPlaying ? '일시정지' : '재생'}
        </button>
        <button
          type="button"
          onClick={() => stop()}
          disabled={tracks.length === 0}
          style={{
            padding: '6px 10px',
            borderRadius: 6,
            border: '1px solid rgba(148,163,184,0.45)',
            background: 'rgba(30,41,59,0.8)',
            color: '#e2e8f0',
            cursor: 'pointer',
          }}
        >
          정지
        </button>
        <label style={{ fontSize: 12, display: 'flex', alignItems: 'center', gap: 4 }}>
          배속
          <select
            value={playbackSpeed}
            onChange={(event) => setPlaybackSpeed(Number(event.target.value))}
            style={{
              background: 'rgba(30,41,59,0.85)',
              border: '1px solid rgba(148,163,184,0.45)',
              borderRadius: 6,
              color: '#e2e8f0',
              fontSize: 12,
              padding: '4px 6px',
            }}
          >
            {TRACK_PLAYBACK_SPEED_OPTIONS.map((speed) => (
              <option key={speed} value={speed}>
                {speed}x
              </option>
            ))}
          </select>
        </label>
      </div>

      <div style={{ marginBottom: 10 }}>
        <input
          type="range"
          min={startTime}
          max={endTime || startTime + 1}
          value={currentTime}
          onChange={(event) => setCurrentTime(Number(event.target.value))}
          style={{ width: '100%' }}
          disabled={tracks.length === 0 || endTime <= startTime}
        />
        <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 11, color: '#94a3b8' }}>
          <span>{formatDateTime(currentTime)}</span>
          <span>{Math.max(0, Math.min(100, progress)).toFixed(1)}%</span>
        </div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 6, fontSize: 12 }}>
        <label>
          <input type="checkbox" checked={showPoints} onChange={(event) => setShowPoints(event.target.checked)} /> 포인트
        </label>
        <label>
          <input
            type="checkbox"
            checked={showVirtualShip}
            onChange={(event) => setShowVirtualShip(event.target.checked)}
          />{' '}
          가상선박
        </label>
        <label>
          <input type="checkbox" checked={showLabels} onChange={(event) => setShowLabels(event.target.checked)} /> 선명
        </label>
        <label>
          <input type="checkbox" checked={showTrail} onChange={(event) => setShowTrail(event.target.checked)} /> 잔상
        </label>
        <label>
          <input
            type="checkbox"
            checked={hideLiveShips}
            onChange={(event) => setHideLiveShips(event.target.checked)}
          />{' '}
          라이브 숨김
        </label>
        <label>
          <input type="checkbox" checked={loop} onChange={() => toggleLoop()} /> 반복
        </label>
      </div>
    </div>
  );
}
