import { useState, useEffect, useRef } from 'react';
import { Loader2, Maximize2, Minimize2, Play, Pause, Volume2, VolumeX, Captions, Languages } from 'lucide-react';
import { getExt, formatTime, getRawUrl, getSubtitlesUrl, getSubtitleVttUrl, getAudioTracksUrl } from '../file-types';
import { useSeekBar, SeekBar } from './SeekBar';

type VideoRendererProps = {
  src: string;
  fileName: string;
  filePath: string;
  root?: string;
};

type SubtitleTrack = { id: number; lang: string; label: string };
type AudioOption = { id: number; label: string };

export const VideoRenderer = ({ src, fileName, filePath, root }: VideoRendererProps) => {
  const videoRef = useRef<HTMLVideoElement>(null);
  const containerRef = useRef<HTMLDivElement>(null);
  const hideTimer = useRef<ReturnType<typeof setTimeout>>(null);
  // When we swap the source to switch audio track, restore the playhead + play state after it loads.
  const pendingSeek = useRef<{ time: number; play: boolean } | null>(null);
  const [playing, setPlaying] = useState(false);
  const [currentTime, setCurrent] = useState(0);
  const [duration, setDuration] = useState(0);
  const [volume, setVolume] = useState(1);
  const [muted, setMuted] = useState(false);
  const [loaded, setLoaded] = useState(false);
  const [error, setError] = useState(false);
  const [showControls, setShowControls] = useState(true);
  const [isFullscreen, setIsFullscreen] = useState(false);
  const [videoSrc, setVideoSrc] = useState(src);
  const [subtitles, setSubtitles] = useState<SubtitleTrack[]>([]);
  const [activeSub, setActiveSub] = useState<number | null>(null);
  const [showSubMenu, setShowSubMenu] = useState(false);
  const [audioTracks, setAudioTracks] = useState<AudioOption[]>([]);
  const [activeAudio, setActiveAudio] = useState(0);
  const [showAudioMenu, setShowAudioMenu] = useState(false);
  const { barRef, onSeekDown } = useSeekBar(videoRef, duration);

  // New file → reset to its default source / audio track.
  useEffect(() => {
    setVideoSrc(src);
    setActiveAudio(0);
    pendingSeek.current = null;
  }, [src]);

  useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    const onLoaded = () => {
      setDuration(v.duration);
      setLoaded(true);
      const ps = pendingSeek.current;
      if (ps) {
        pendingSeek.current = null;
        try {
          v.currentTime = ps.time;
        } catch {
          /* ignore */
        }
        if (ps.play) v.play().catch(() => {});
      }
    };
    const onTime = () => setCurrent(v.currentTime);
    const onPlay = () => setPlaying(true);
    const onPause = () => setPlaying(false);
    const onEnded = () => setPlaying(false);
    const onError = () => {
      // Aborts happen when we swap the source to switch audio — don't treat those as fatal.
      const err = v.error;
      if (err && err.code !== err.MEDIA_ERR_ABORTED) setError(true);
    };
    v.addEventListener('loadedmetadata', onLoaded);
    v.addEventListener('timeupdate', onTime);
    v.addEventListener('play', onPlay);
    v.addEventListener('pause', onPause);
    v.addEventListener('ended', onEnded);
    v.addEventListener('error', onError);
    return () => {
      v.removeEventListener('loadedmetadata', onLoaded);
      v.removeEventListener('timeupdate', onTime);
      v.removeEventListener('play', onPlay);
      v.removeEventListener('pause', onPause);
      v.removeEventListener('ended', onEnded);
      v.removeEventListener('error', onError);
    };
  }, []);

  // Reload cleanly whenever the source changes (default ↔ an audio-switched remux).
  useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    setError(false);
    setLoaded(false);
    v.load();
  }, [videoSrc]);

  // Discover embedded subtitle tracks (served on demand as WebVTT via <track>)
  useEffect(() => {
    let cancelled = false;
    setSubtitles([]);
    setActiveSub(null);
    fetch(getSubtitlesUrl(filePath, root))
      .then((res) => (res.ok ? res.json() : []))
      .then((list: Array<{ id: number; lang: string; title: string }>) => {
        if (cancelled || !Array.isArray(list)) return;
        setSubtitles(
          list.map((t) => {
            const realLang = t.lang && t.lang !== 'und' && t.lang !== 'unknown' ? t.lang.toUpperCase() : '';
            return { id: t.id, lang: t.lang || 'und', label: t.title || realLang || `Track ${t.id + 1}` };
          }),
        );
      })
      .catch(() => {});
    return () => {
      cancelled = true;
    };
  }, [filePath, root]);

  // Discover audio tracks (switched server-side by reloading the source with the chosen track)
  useEffect(() => {
    let cancelled = false;
    setAudioTracks([]);
    fetch(getAudioTracksUrl(filePath, root))
      .then((res) => (res.ok ? res.json() : []))
      .then((list: Array<{ id: number; lang: string; title: string }>) => {
        if (cancelled || !Array.isArray(list)) return;
        setAudioTracks(
          list.map((t) => {
            const realLang = t.lang && t.lang !== 'und' && t.lang !== 'unknown' ? t.lang.toUpperCase() : '';
            return { id: t.id, label: t.title || realLang || `Track ${t.id + 1}` };
          }),
        );
      })
      .catch(() => {});
    return () => {
      cancelled = true;
    };
  }, [filePath, root]);

  useEffect(() => {
    const onChange = () => setIsFullscreen(!!document.fullscreenElement);
    document.addEventListener('fullscreenchange', onChange);
    return () => document.removeEventListener('fullscreenchange', onChange);
  }, []);

  const resetHideTimer = () => {
    setShowControls(true);
    if (hideTimer.current) clearTimeout(hideTimer.current);
    hideTimer.current = setTimeout(() => {
      if (videoRef.current && !videoRef.current.paused) setShowControls(false);
    }, 2500);
  };

  const togglePlay = () => {
    const v = videoRef.current;
    if (!v) return;
    if (v.paused) v.play();
    else v.pause();
  };

  const changeVolume = (ev: React.ChangeEvent<HTMLInputElement>) => {
    const val = parseFloat(ev.target.value);
    setVolume(val);
    setMuted(val === 0);
    if (videoRef.current) videoRef.current.volume = val;
  };

  const toggleMute = () => {
    const v = videoRef.current;
    if (!v) return;
    if (muted) {
      v.volume = volume || 1;
      setMuted(false);
    } else {
      v.volume = 0;
      setMuted(true);
    }
  };

  const toggleFullscreen = () => {
    const c = containerRef.current;
    if (!c) return;
    if (document.fullscreenElement) document.exitFullscreen();
    else c.requestFullscreen();
  };

  // Only one text track shows at a time; null turns them all off.
  const selectSubtitle = (id: number | null) => {
    const v = videoRef.current;
    if (v) {
      for (let i = 0; i < v.textTracks.length; i++) {
        v.textTracks[i]!.mode = i === id ? 'showing' : 'disabled';
      }
    }
    setActiveSub(id);
    setShowSubMenu(false);
  };

  // Switch audio track by reloading the source (track 0 = the raw file; others are remuxed server-side).
  const selectAudio = (track: number) => {
    setShowAudioMenu(false);
    if (track === activeAudio) return;
    const v = videoRef.current;
    if (v) pendingSeek.current = { time: v.currentTime, play: !v.paused };
    setActiveAudio(track);
    setLoaded(false);
    setVideoSrc(track === 0 ? src : getRawUrl(filePath, root, track));
  };

  const pct = duration > 0 ? (currentTime / duration) * 100 : 0;

  if (error) {
    return (
      <div className="flex items-center justify-center h-full">
        <span className="text-sm text-red-500">Failed to load video</span>
      </div>
    );
  }

  return (
    <div
      ref={containerRef}
      className="relative w-full h-full bg-black flex items-center justify-center group"
      onMouseMove={resetHideTimer}
      onMouseLeave={() => {
        if (playing) setShowControls(false);
      }}
    >
      <video ref={videoRef} src={videoSrc} preload="metadata" playsInline className="w-full h-full object-contain" onClick={togglePlay}>
        {subtitles.map((t) => (
          <track key={t.id} kind="subtitles" src={getSubtitleVttUrl(filePath, t.id, root)} srcLang={t.lang} label={t.label} />
        ))}
      </video>

      {/* Audio-track selector — outside the auto-hiding controls, always visible */}
      {audioTracks.length > 1 && (
        <div className="absolute top-2 left-2 z-10">
          <button
            onClick={() => setShowAudioMenu((s) => !s)}
            className="flex items-center gap-1.5 px-2 py-1 rounded-md bg-black/50 backdrop-blur-sm text-xs text-white/90 hover:bg-black/70 transition-colors cursor-pointer"
            title="Audio track"
          >
            <Languages className="h-3.5 w-3.5" />
            <span className="max-w-[140px] truncate">{audioTracks[activeAudio]?.label ?? 'Audio'}</span>
          </button>
          {showAudioMenu && (
            <div className="absolute top-full left-0 mt-1 min-w-[160px] max-h-64 overflow-y-auto rounded-md bg-black/90 backdrop-blur-sm py-1 text-xs shadow-lg">
              {audioTracks.map((t, i) => (
                <button
                  key={t.id}
                  onClick={() => selectAudio(i)}
                  className={`w-full text-left px-3 py-1.5 hover:bg-white/10 cursor-pointer truncate ${activeAudio === i ? 'text-duck-teal' : 'text-white/80'}`}
                >
                  {t.label}
                </button>
              ))}
            </div>
          )}
        </div>
      )}

      {loaded && !playing && (
        <button onClick={togglePlay} className="absolute inset-0 flex items-center justify-center cursor-pointer">
          <div className="w-16 h-16 rounded-full bg-black/50 backdrop-blur-sm flex items-center justify-center">
            <Play className="h-8 w-8 text-white ml-1" />
          </div>
        </button>
      )}

      {!loaded && (
        <div className="absolute inset-0 flex items-center justify-center">
          <Loader2 className="h-8 w-8 text-white animate-spin" />
        </div>
      )}

      <div
        className={`absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 via-black/40 to-transparent pt-12 pb-3 px-4 transition-opacity duration-300 ${
          showControls || !playing ? 'opacity-100' : 'opacity-0 pointer-events-none'
        }`}
      >
        <SeekBar
          barRef={barRef}
          onSeekDown={onSeekDown}
          pct={pct}
          trackClass="bg-white/20"
          fillClass="bg-duck-teal"
          thumbClass="bg-duck-teal border-white"
        />

        <div className="flex items-center gap-3 mt-1">
          <button onClick={togglePlay} className="p-1 text-white hover:text-duck-teal transition-colors cursor-pointer">
            {playing ? <Pause className="h-5 w-5" /> : <Play className="h-5 w-5" />}
          </button>

          <div className="flex items-center gap-1.5">
            <button onClick={toggleMute} className="p-1 text-white/70 hover:text-white transition-colors cursor-pointer">
              {muted ? <VolumeX className="h-4 w-4" /> : <Volume2 className="h-4 w-4" />}
            </button>
            <input
              type="range"
              min={0}
              max={1}
              step={0.01}
              value={muted ? 0 : volume}
              onChange={changeVolume}
              className="w-16 h-1 accent-duck-teal cursor-pointer"
            />
          </div>

          <span className="text-xs font-mono text-white/60 select-none">
            {formatTime(currentTime)} / {formatTime(duration)}
          </span>

          <div className="flex-1" />

          <span className="text-[9px] font-mono text-white/30 uppercase tracking-wider">{getExt(fileName)}</span>

          {subtitles.length > 0 && (
            <div className="relative">
              <button
                onClick={() => setShowSubMenu((s) => !s)}
                className={`p-1 transition-colors cursor-pointer ${activeSub !== null ? 'text-duck-teal' : 'text-white/70 hover:text-white'}`}
                title="Subtitles"
                aria-label="Subtitles"
              >
                <Captions className="h-4 w-4" />
              </button>
              {showSubMenu && (
                <div className="absolute bottom-full right-0 mb-2 min-w-[140px] max-h-64 overflow-y-auto rounded-md bg-black/90 backdrop-blur-sm py-1 text-xs shadow-lg">
                  <button
                    onClick={() => selectSubtitle(null)}
                    className={`w-full text-left px-3 py-1.5 hover:bg-white/10 cursor-pointer ${activeSub === null ? 'text-duck-teal' : 'text-white/80'}`}
                  >
                    Off
                  </button>
                  {subtitles.map((t) => (
                    <button
                      key={t.id}
                      onClick={() => selectSubtitle(t.id)}
                      className={`w-full text-left px-3 py-1.5 hover:bg-white/10 cursor-pointer truncate ${activeSub === t.id ? 'text-duck-teal' : 'text-white/80'}`}
                    >
                      {t.label}
                    </button>
                  ))}
                </div>
              )}
            </div>
          )}

          <button onClick={toggleFullscreen} className="p-1 text-white/70 hover:text-white transition-colors cursor-pointer">
            {isFullscreen ? <Minimize2 className="h-4 w-4" /> : <Maximize2 className="h-4 w-4" />}
          </button>
        </div>
      </div>
    </div>
  );
};
