"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { mediaUrl } from "@/app/lib/media";

const STORAGE_PREFIX = "lms-video-";
const SAVE_INTERVAL = 5000;
const MIN_PROGRESS_TO_SHOW = 10;

function getStoredProgress(videoId: string): number {
  if (typeof window === "undefined") return 0;
  try {
    const raw = localStorage.getItem(`${STORAGE_PREFIX}${videoId}`);
    if (!raw) return 0;
    const data = JSON.parse(raw);
    return typeof data?.time === "number" ? data.time : 0;
  } catch {
    return 0;
  }
}

function saveProgress(videoId: string, time: number): void {
  if (typeof window === "undefined") return;
  try {
    localStorage.setItem(`${STORAGE_PREFIX}${videoId}`, JSON.stringify({ time }));
  } catch {
    /* ignore */
  }
}

type VideoPlayerProps = {
  src: string;
  poster?: string;
  title?: string;
  className?: string;
  videoId?: string;
  onComplete?: () => void;
};

export function VideoPlayer({ src, poster, title, className = "", videoId, onComplete }: VideoPlayerProps) {
  const videoRef = useRef<HTMLVideoElement>(null);
  const [playing, setPlaying] = useState(false);
  const [progress, setProgress] = useState(0);
  const [currentTime, setCurrentTime] = useState(0);
  const [duration, setDuration] = useState(0);
  const [volume, setVolume] = useState(1);
  const [muted, setMuted] = useState(false);
  const [speed, setSpeed] = useState(1);
  const [showControls, setShowControls] = useState(true);
  const [showResumePrompt, setShowResumePrompt] = useState(false);
  const [savedTime, setSavedTime] = useState(0);
  const hideTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const lastSaveRef = useRef(0);

  const togglePlay = useCallback(() => {
    const v = videoRef.current;
    if (!v) return;
    if (v.paused) {
      v.play();
      setPlaying(true);
    } else {
      v.pause();
      setPlaying(false);
    }
  }, []);

  const handleTimeUpdate = useCallback(() => {
    const v = videoRef.current;
    if (!v) return;
    const time = v.currentTime;
    const dur = v.duration;
    setCurrentTime(time);
    setProgress(Number.isFinite(dur) && dur > 0 ? (time / dur) * 100 : 0);

    if (videoId && v.currentTime > 0) {
      const now = Date.now();
      if (now - lastSaveRef.current > SAVE_INTERVAL) {
        lastSaveRef.current = now;
        saveProgress(videoId, v.currentTime);
      }
    }
  }, [videoId]);

  const handleLoadedMetadata = useCallback(() => {
    const v = videoRef.current;
    if (!v) return;
    const dur = v.duration;
    if (!Number.isFinite(dur) || dur <= 0) return;
    setDuration(dur);

    if (videoId) {
      const stored = getStoredProgress(videoId);
      if (Number.isFinite(stored) && stored >= MIN_PROGRESS_TO_SHOW && stored < dur - 5) {
        setSavedTime(stored);
        setShowResumePrompt(true);
      }
    }
  }, [videoId]);

  const handleEnded = useCallback(() => {
    setPlaying(false);
    setProgress(0);
    setCurrentTime(0);
    if (videoId) saveProgress(videoId, 0);
    onComplete?.();
  }, [videoId, onComplete]);

  const handlePause = useCallback(() => {
    const v = videoRef.current;
    if (videoId && v && v.currentTime > 0) {
      saveProgress(videoId, v.currentTime);
    }
  }, [videoId]);

  const handleResume = useCallback(() => {
    const v = videoRef.current;
    if (!v || savedTime <= 0) return;
    const dur = v.duration;
    if (!Number.isFinite(dur) || dur <= 0) return;
    const time = Math.min(savedTime, dur - 0.1);
    v.currentTime = time;
    setCurrentTime(time);
    setProgress((time / dur) * 100);
    v.play();
    setPlaying(true);
    setShowResumePrompt(false);
  }, [savedTime]);

  const handleRestart = useCallback(() => {
    const v = videoRef.current;
    if (!v) return;
    if (videoId) saveProgress(videoId, 0);
    v.currentTime = 0;
    setCurrentTime(0);
    setProgress(0);
    setShowResumePrompt(false);
  }, [videoId]);

  const handleSeek = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
    const v = videoRef.current;
    if (!v) return;
    const dur = v.duration;
    if (!Number.isFinite(dur) || dur <= 0) return;
    const rect = e.currentTarget.getBoundingClientRect();
    if (rect.width <= 0) return;
    const p = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
    const time = p * dur;
    v.currentTime = time;
    setCurrentTime(time);
    setProgress(p * 100);
  }, []);

  const toggleMute = useCallback(() => {
    const v = videoRef.current;
    if (!v) return;
    v.muted = !v.muted;
    setMuted(v.muted);
  }, []);

  const handleVolumeChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const v = videoRef.current;
    if (!v) return;
    const val = parseFloat(e.target.value);
    v.volume = val;
    setVolume(val);
    setMuted(val === 0);
  }, []);

  const cycleSpeed = useCallback(() => {
    const speeds = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
    const i = speeds.indexOf(speed);
    const next = speeds[(i + 1) % speeds.length];
    const v = videoRef.current;
    if (v) v.playbackRate = next;
    setSpeed(next);
  }, [speed]);

  const toggleFullscreen = useCallback(() => {
    const container = videoRef.current?.parentElement;
    if (!container) return;
    if (!document.fullscreenElement) {
      container.requestFullscreen();
    } else {
      document.exitFullscreen();
    }
  }, []);

  const showControlsTemporarily = useCallback(() => {
    setShowControls(true);
    if (hideTimerRef.current) clearTimeout(hideTimerRef.current);
    hideTimerRef.current = setTimeout(() => setShowControls(false), 3000);
  }, []);

  useEffect(() => () => { if (hideTimerRef.current) clearTimeout(hideTimerRef.current); }, []);

  const formatTime = (s: number) => {
    if (!Number.isFinite(s) || s < 0) return "0:00";
    const m = Math.floor(s / 60);
    const sec = Math.floor(s % 60);
    return `${m}:${sec.toString().padStart(2, "0")}`;
  };

  const formatResumeTime = (s: number) => {
    if (!Number.isFinite(s) || s < 0) return "0秒";
    const m = Math.floor(s / 60);
    const sec = Math.floor(s % 60);
    if (m > 0) return `${m}分${sec}秒`;
    return `${sec}秒`;
  };

  return (
    <div
      className={`group relative overflow-hidden rounded-xl bg-black md:rounded-2xl ${className}`}
      onMouseMove={showControlsTemporarily}
      onMouseLeave={() => setShowControls(false)}
    >
      <video
        ref={videoRef}
        src={mediaUrl(src)}
        poster={mediaUrl(poster)}
        title={title}
        className="aspect-video w-full object-contain"
        onClick={togglePlay}
        onTimeUpdate={handleTimeUpdate}
        onLoadedMetadata={handleLoadedMetadata}
        onEnded={handleEnded}
        onPause={handlePause}
        playsInline
      />

      {showResumePrompt && (
        <div className="absolute bottom-20 left-3 z-10 max-w-[280px] rounded-lg bg-black/85 px-4 py-3 shadow-xl backdrop-blur sm:left-4 sm:bottom-24">
          <p className="mb-3 text-sm text-white/90">
            上次看到 <span className="font-semibold text-white">{formatResumeTime(savedTime)}</span>
          </p>
          <div className="flex gap-2">
            <button
              type="button"
              onClick={handleResume}
              className="flex-1 rounded-md bg-[var(--accent)] px-3 py-2 text-sm font-medium text-black transition hover:opacity-90"
            >
              从上次继续
            </button>
            <button
              type="button"
              onClick={handleRestart}
              className="rounded-md border border-white/30 bg-white/10 px-3 py-2 text-sm text-white transition hover:bg-white/20"
            >
              重新观看
            </button>
          </div>
        </div>
      )}

      {!playing && (
        <button
          type="button"
          onClick={togglePlay}
          className="absolute inset-0 flex items-center justify-center bg-black/20 transition hover:bg-black/30"
          aria-label="播放"
        >
          <div className="flex h-16 w-16 items-center justify-center rounded-full bg-white/90 shadow-lg transition hover:scale-110 sm:h-20 sm:w-20">
            <svg
              className="ml-1 h-8 w-8 text-black sm:h-10 sm:w-10"
              fill="currentColor"
              viewBox="0 0 24 24"
            >
              <path d="M8 5v14l11-7z" />
            </svg>
          </div>
        </button>
      )}

      <div
        className={`absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/90 to-transparent p-3 transition-opacity duration-300 ${
          showControls ? "opacity-100" : "opacity-0"
        }`}
      >
        <div
          className="mb-3 h-1 cursor-pointer rounded-full bg-white/30"
          onClick={handleSeek}
          role="slider"
          aria-valuenow={progress}
        >
          <div
            className="h-full rounded-full bg-[var(--accent)] transition-all"
            style={{ width: `${progress}%` }}
          />
        </div>

        <div className="flex items-center gap-2 sm:gap-4">
          <button
            type="button"
            onClick={togglePlay}
            className="rounded p-1 text-white transition hover:bg-white/20"
            aria-label={playing ? "暂停" : "播放"}
          >
            {playing ? (
              <svg className="h-5 w-5 sm:h-6 sm:w-6" fill="currentColor" viewBox="0 0 24 24">
                <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
              </svg>
            ) : (
              <svg className="h-5 w-5 sm:h-6 sm:w-6" fill="currentColor" viewBox="0 0 24 24">
                <path d="M8 5v14l11-7z" />
              </svg>
            )}
          </button>

          <span className="min-w-[4rem] text-xs text-white/90 sm:text-sm">
            {formatTime(currentTime)} / {formatTime(duration)}
          </span>

          <div className="flex items-center gap-1">
            <button
              type="button"
              onClick={toggleMute}
              className="rounded p-1 text-white transition hover:bg-white/20"
              aria-label={muted ? "取消静音" : "静音"}
            >
              {muted || volume === 0 ? (
                <svg className="h-5 w-5 sm:h-6 sm:w-6" fill="currentColor" viewBox="0 0 24 24">
                  <path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z" />
                </svg>
              ) : (
                <svg className="h-5 w-5 sm:h-6 sm:w-6" fill="currentColor" viewBox="0 0 24 24">
                  <path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z" />
                </svg>
              )}
            </button>
            <input
              type="range"
              min="0"
              max="1"
              step="0.1"
              value={muted ? 0 : volume}
              onChange={handleVolumeChange}
              className="h-1 w-16 cursor-pointer accent-[var(--accent)] sm:w-20"
            />
          </div>

          <button
            type="button"
            onClick={cycleSpeed}
            className="rounded px-2 py-1 text-xs font-medium text-white/90 transition hover:bg-white/20 sm:text-sm"
          >
            {speed}x
          </button>

          <button
            type="button"
            onClick={toggleFullscreen}
            className="ml-auto rounded p-1 text-white transition hover:bg-white/20"
            aria-label="全屏"
          >
            <svg className="h-5 w-5 sm:h-6 sm:w-6" fill="currentColor" viewBox="0 0 24 24">
              <path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" />
            </svg>
          </button>
        </div>
      </div>
    </div>
  );
}
