/* eslint-disable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-explicit-any, react-hooks/exhaustive-deps, no-console, @next/next/no-img-element */

'use client';

import {
  type MediaProviderAdapter,
  AirPlayButton,
  isHLSProvider,
  MediaPlayer,
  MediaProvider,
} from '@vidstack/react';
import { AirPlayIcon } from '@vidstack/react/icons';
import {
  defaultLayoutIcons,
  DefaultVideoLayout,
} from '@vidstack/react/player/layouts/default';
import Hls from 'hls.js';
import { Heart } from 'lucide-react';
import { useSearchParams } from 'next/navigation';
import { Suspense } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import React from 'react';

import 'vidstack/styles/defaults.css';
import '@vidstack/react/player/styles/default/theme.css';
import '@vidstack/react/player/styles/default/layouts/video.css';

import {
  deletePlayRecord,
  generateStorageKey,
  getAllPlayRecords,
  isFavorited,
  savePlayRecord,
  toggleFavorite,
} from '@/lib/db.client';
import { type VideoDetail, fetchVideoDetail } from '@/lib/fetchVideoDetail';

// 扩展 HTMLVideoElement 类型以支持 hls 属性
declare global {
  interface HTMLVideoElement {
    hls?: any;
  }
}

// 搜索结果类型
interface SearchResult {
  id: string;
  title: string;
  poster: string;
  episodes: string[];
  source: string;
  source_name: string;
  year: string;
}

function PlayPageClient() {
  const searchParams = useSearchParams();
  // @ts-ignore
  const playerRef = useRef<any>(null);
  const playerContainerRef = useRef<HTMLDivElement>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  // 使用 useState 保存视频详情
  const [detail, setDetail] = useState<VideoDetail | null>(null);

  // 初始标题：如果 URL 中携带 title 参数，则优先使用
  const [videoTitle, setVideoTitle] = useState(searchParams.get('title') || '');
  const videoYear = searchParams.get('year') || '';
  const [videoCover, setVideoCover] = useState('');

  const [currentSource, setCurrentSource] = useState(
    searchParams.get('source') || ''
  );
  const [currentId, setCurrentId] = useState(searchParams.get('id') || '');
  const [sourceChanging, setSourceChanging] = useState(false);
  const initialIndex = parseInt(searchParams.get('index') || '1') - 1; // 转换为0基数组索引

  const [currentEpisodeIndex, setCurrentEpisodeIndex] = useState(initialIndex);
  const [showEpisodePanel, setShowEpisodePanel] = useState(false);
  const [showSourcePanel, setShowSourcePanel] = useState(false);
  const [showShortcutHint, setShowShortcutHint] = useState(false);
  const [shortcutText, setShortcutText] = useState('');
  const [shortcutDirection, setShortcutDirection] = useState('');
  const shortcutHintTimeoutRef = useRef<NodeJS.Timeout | null>(null);

  // 换源相关状态
  const [searchResults, setSearchResults] = useState<SearchResult[]>([]);
  const [searchLoading, setSearchLoading] = useState(false);
  const [searchError, setSearchError] = useState<string | null>(null);
  const hasSearchedRef = useRef(false);

  // 视频播放地址
  const [videoUrl, setVideoUrl] = useState('');

  // 播放进度保存相关
  const saveIntervalRef = useRef<NodeJS.Timeout | null>(null);
  const lastSaveTimeRef = useRef<number>(0);

  // 总集数：从 detail 中获取，保证随 detail 更新而变化
  const totalEpisodes = detail?.episodes?.length || 0;

  // 收藏状态
  const [favorited, setFavorited] = useState(false);
  // 是否显示旋转提示（5s 后自动隐藏）
  const [showOrientationTip, setShowOrientationTip] = useState(false);
  const orientationTipTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  // 当前是否处于竖屏，用于控制"强制横屏"按钮显隐
  const [isPortrait, setIsPortrait] = useState(
    typeof window !== 'undefined'
      ? window.matchMedia('(orientation: portrait)').matches
      : true
  );
  const [isFullscreen, setIsFullscreen] = useState(false);

  // 长按三倍速相关状态
  const [isLongPressing, setIsLongPressing] = useState(false);
  const [showSpeedTip, setShowSpeedTip] = useState(false);
  const longPressTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const originalPlaybackRateRef = useRef<number>(1);
  const speedTipTimeoutRef = useRef<NodeJS.Timeout | null>(null);

  // 用于记录是否需要在播放器 ready 后跳转到指定进度
  const resumeTimeRef = useRef<number | null>(null);

  const currentEpisodeIndexRef = useRef(currentEpisodeIndex);
  const detailRef = useRef<VideoDetail | null>(detail);

  const currentSourceRef = useRef(currentSource);
  const currentIdRef = useRef(currentId);
  const videoTitleRef = useRef(videoTitle);

  // 同步最新值到 refs
  useEffect(() => {
    currentSourceRef.current = currentSource;
    currentIdRef.current = currentId;
    detailRef.current = detail;
    currentEpisodeIndexRef.current = currentEpisodeIndex;
    videoTitleRef.current = videoTitle;
  }, [currentSource, currentId, detail, currentEpisodeIndex, videoTitle]);

  // 解决 iOS Safari 100vh 不准确的问题：将视口高度写入 CSS 变量 --vh
  const setVH = useCallback(() => {
    if (typeof window !== 'undefined') {
      document.documentElement.style.setProperty(
        '--vh',
        `${window.innerHeight * 0.01}px`
      );
    }
  }, []);

  // 解决 iOS Safari 100vh 不准确的问题：将视口高度写入 CSS 变量 --vh
  useEffect(() => {
    setVH();
    window.addEventListener('resize', setVH);
    window.addEventListener('orientationchange', setVH);
    return () => {
      window.removeEventListener('resize', setVH);
      window.removeEventListener('orientationchange', setVH);
    };
  }, [setVH]);

  // 根据 detail 和集数索引更新视频地址（仅当地址真正变化时）
  const updateVideoUrl = (
    detailData: VideoDetail | null,
    episodeIndex: number
  ) => {
    if (
      !detailData ||
      !detailData.episodes ||
      episodeIndex >= detailData.episodes.length
    ) {
      setVideoUrl('');
      return;
    }
    const newUrl = detailData?.episodes[episodeIndex] || '';
    if (newUrl !== videoUrl) {
      setVideoUrl(newUrl);
      playerContainerRef.current?.focus();
    }
  };

  // 当集数索引变化时自动更新视频地址
  useEffect(() => {
    updateVideoUrl(detail, currentEpisodeIndex);
  }, [detail, currentEpisodeIndex]);

  // 确保初始状态与URL参数同步
  useEffect(() => {
    const urlSource = searchParams.get('source');
    const urlId = searchParams.get('id');

    if (urlSource && urlSource !== currentSource) {
      setCurrentSource(urlSource);
    }
    if (urlId && urlId !== currentId) {
      setCurrentId(urlId);
    }
  }, [searchParams, currentSource, currentId]);

  useEffect(() => {
    if (!currentSource || !currentId) {
      setError('缺少必要参数');
      setLoading(false);
      return;
    }

    const fetchDetail = async () => {
      try {
        const detailData = await fetchVideoDetail({
          source: currentSource,
          id: currentId,
          fallbackTitle: videoTitle,
          fallbackYear: videoYear,
        });

        // 更新状态保存详情
        setVideoTitle(detailData.title || videoTitle);
        setVideoCover(detailData.poster);
        setDetail(detailData);

        // 确保集数索引在有效范围内
        if (currentEpisodeIndex >= detailData.episodes.length) {
          console.log('currentEpisodeIndex', currentEpisodeIndex);
          setCurrentEpisodeIndex(0);
        }

        // 清理URL参数（移除index参数）
        if (searchParams.has('index')) {
          const newUrl = new URL(window.location.href);
          newUrl.searchParams.delete('index');
          newUrl.searchParams.delete('position');
          window.history.replaceState({}, '', newUrl.toString());
        }
      } catch (err) {
        setError(err instanceof Error ? err.message : '获取视频详情失败');
      } finally {
        setLoading(false);
      }
    };

    fetchDetail();
  }, [currentSource]);

  /* -------------------- 播放记录处理 -------------------- */
  useEffect(() => {
    // 仅在初次挂载时检查播放记录
    const initFromHistory = async () => {
      if (!currentSource || !currentId) return;

      try {
        const allRecords = await getAllPlayRecords();
        const key = generateStorageKey(currentSource, currentId);
        const record = allRecords[key];

        // URL 参数
        const urlIndexParam = searchParams.get('index');
        const urlPositionParam = searchParams.get('position');

        // 当index参数存在时的处理逻辑
        if (urlIndexParam) {
          const urlIndex = parseInt(urlIndexParam, 10) - 1;
          let targetTime = 0; // 默认从0开始

          // 只有index参数和position参数都存在时才生效position
          if (urlPositionParam) {
            targetTime = parseInt(urlPositionParam, 10);
          } else if (record && urlIndex === record.index - 1) {
            // 如果有同集播放记录则跳转到播放记录处
            targetTime = record.play_time;
          }
          // 否则从0开始（targetTime已经是0）

          // 更新当前选集索引
          if (urlIndex !== currentEpisodeIndex) {
            setCurrentEpisodeIndex(urlIndex);
          }

          // 保存待恢复的播放进度，待播放器就绪后跳转
          resumeTimeRef.current = targetTime;
        } else if (record) {
          // 没有index参数但有播放记录时，使用原有逻辑
          const targetIndex = record.index - 1;
          const targetTime = record.play_time;

          // 更新当前选集索引
          if (targetIndex !== currentEpisodeIndex) {
            setCurrentEpisodeIndex(targetIndex);
          }

          // 保存待恢复的播放进度，待播放器就绪后跳转
          resumeTimeRef.current = targetTime;
        }
      } catch (err) {
        console.error('读取播放记录失败:', err);
      }
    };

    initFromHistory();
  }, []);

  // 播放器事件处理
  const onCanPlay = () => {
    console.log('播放器准备就绪');
    setError(null);

    // 若存在需要恢复的播放进度，则跳转
    if (
      playerRef.current &&
      resumeTimeRef.current &&
      resumeTimeRef.current > 0
    ) {
      try {
        const duration = playerRef.current.duration || 0;
        let target = resumeTimeRef.current;
        // 如果目标时间距离结尾过近，为避免自动触发下一集，向前偏移 5 秒
        if (duration && target >= duration - 2) {
          target = Math.max(0, duration - 5);
        }
        playerRef.current.currentTime = target;
      } catch (err) {
        console.warn('恢复播放进度失败:', err);
      }
      resumeTimeRef.current = null;
    }
  };

  const onEnded = () => {
    const d = detailRef.current;
    const idx = currentEpisodeIndexRef.current;
    if (d && d.episodes && idx < d.episodes.length - 1) {
      setTimeout(() => {
        setCurrentEpisodeIndex(idx + 1);
      }, 1000);
    }
  };

  const onTimeUpdate = () => {
    const now = Date.now();
    if (now - lastSaveTimeRef.current > 5000) {
      saveCurrentPlayProgress();
      lastSaveTimeRef.current = now;
    }
  };

  const handlePlayerError = (e: any) => {
    console.error('播放器错误:', e);
    setError('视频播放失败');
  };

  // 页面卸载和隐藏时保存播放进度
  useEffect(() => {
    // 页面即将卸载时保存播放进度
    const handleBeforeUnload = () => {
      saveCurrentPlayProgress();
    };

    // 页面可见性变化时保存播放进度
    const handleVisibilityChange = () => {
      if (document.visibilityState === 'hidden') {
        saveCurrentPlayProgress();
      }
    };

    // 添加事件监听器
    window.addEventListener('beforeunload', handleBeforeUnload);
    document.addEventListener('visibilitychange', handleVisibilityChange);

    return () => {
      // 清理事件监听器
      window.removeEventListener('beforeunload', handleBeforeUnload);
      document.removeEventListener('visibilitychange', handleVisibilityChange);
    };
  }, [currentEpisodeIndex, detail, playerRef.current]);

  // 清理定时器
  useEffect(() => {
    return () => {
      if (shortcutHintTimeoutRef.current) {
        clearTimeout(shortcutHintTimeoutRef.current);
      }
      if (saveIntervalRef.current) {
        clearInterval(saveIntervalRef.current);
      }
      if (longPressTimeoutRef.current) {
        clearTimeout(longPressTimeoutRef.current);
      }
      if (speedTipTimeoutRef.current) {
        clearTimeout(speedTipTimeoutRef.current);
      }
    };
  }, []);

  // 当视频标题变化时重置搜索状态
  useEffect(() => {
    if (videoTitle) {
      hasSearchedRef.current = false;
      setSearchResults([]);
      setSearchError(null);
    }
  }, [videoTitle]);

  // 添加键盘事件监听器 (使用 refs 避免重复绑定)
  useEffect(() => {
    document.addEventListener('keydown', handleKeyboardShortcuts);
    return () => {
      document.removeEventListener('keydown', handleKeyboardShortcuts);
    };
  }, []);

  // 处理选集切换
  const handleEpisodeChange = (episodeIndex: number) => {
    if (episodeIndex >= 0 && episodeIndex < totalEpisodes) {
      // 在更换集数前保存当前播放进度
      if (playerRef.current && !playerRef.current.paused) {
        saveCurrentPlayProgress();
      }
      setCurrentEpisodeIndex(episodeIndex);
      setShowEpisodePanel(false);
    }
  };

  // 处理下一集
  const handleNextEpisode = () => {
    const d = detailRef.current;
    const idx = currentEpisodeIndexRef.current;
    if (d && d.episodes && idx < d.episodes.length - 1) {
      if (playerRef.current && !playerRef.current.paused) {
        saveCurrentPlayProgress();
      }
      setCurrentEpisodeIndex(idx + 1);
    }
  };

  // 处理上一集
  const handlePreviousEpisode = () => {
    const idx = currentEpisodeIndexRef.current;
    if (detailRef.current && idx > 0) {
      if (playerRef.current && !playerRef.current.paused) {
        saveCurrentPlayProgress();
      }
      setCurrentEpisodeIndex(idx - 1);
    }
  };

  // 搜索视频源
  const handleSearch = async (query: string) => {
    if (!query.trim()) {
      setSearchResults([]);
      return;
    }

    setSearchLoading(true);
    setSearchError(null);

    try {
      const response = await fetch(
        `/api/search?q=${encodeURIComponent(query)}`
      );
      if (!response.ok) {
        throw new Error('搜索失败');
      }
      const data = await response.json();

      // 处理搜索结果：每个数据源只展示一个，优先展示与title同名的结果
      const processedResults: SearchResult[] = [];
      const sourceMap = new Map<string, SearchResult[]>();

      // 按数据源分组
      data.results?.forEach((result: SearchResult) => {
        if (!sourceMap.has(result.source)) {
          sourceMap.set(result.source, []);
        }
        const list = sourceMap.get(result.source);
        if (list) {
          list.push(result);
        }
      });

      // 为每个数据源选择最佳结果
      sourceMap.forEach((results) => {
        if (results.length === 0) return;

        // 只选择和当前视频标题完全匹配的结果，如果有年份，还需要年份完全匹配
        const exactMatch = results.find(
          (result) =>
            result.title.toLowerCase() === videoTitle.toLowerCase() &&
            (videoYear
              ? result.year.toLowerCase() === videoYear.toLowerCase()
              : true)
        );

        if (exactMatch) {
          processedResults.push(exactMatch);
          return;
        }
      });

      setSearchResults(processedResults);
    } catch (err) {
      setSearchError(err instanceof Error ? err.message : '搜索失败');
      setSearchResults([]);
    } finally {
      setSearchLoading(false);
    }
  };

  // 处理换源
  const handleSourceChange = async (
    newSource: string,
    newId: string,
    newTitle: string
  ) => {
    try {
      // 记录当前播放进度（仅在同一集数切换时恢复）
      const currentPlayTime = playerRef.current?.currentTime || 0;

      // 显示换源加载状态
      setSourceChanging(true);
      setError(null);

      // 清除前一个历史记录
      if (currentSource && currentId) {
        try {
          await deletePlayRecord(currentSource, currentId);
          console.log('已清除前一个播放记录');
        } catch (err) {
          console.error('清除播放记录失败:', err);
        }
      }

      // 获取新源的详情
      const newDetail = await fetchVideoDetail({
        source: newSource,
        id: newId,
        fallbackTitle: newTitle,
        fallbackYear: videoYear,
      });

      // 尝试跳转到当前正在播放的集数
      let targetIndex = currentEpisodeIndex;

      // 如果当前集数超出新源的范围，则跳转到第一集
      if (!newDetail.episodes || targetIndex >= newDetail.episodes.length) {
        targetIndex = 0;
      }

      // 如果仍然是同一集数且播放进度有效，则在播放器就绪后恢复到原始进度
      if (targetIndex === currentEpisodeIndex && currentPlayTime > 1) {
        resumeTimeRef.current = currentPlayTime;
      } else {
        // 否则从头开始播放，防止影响后续选集逻辑
        resumeTimeRef.current = 0;
      }

      // 更新URL参数（不刷新页面）
      const newUrl = new URL(window.location.href);
      newUrl.searchParams.set('source', newSource);
      newUrl.searchParams.set('id', newId);
      window.history.replaceState({}, '', newUrl.toString());

      // 关闭换源面板
      setShowSourcePanel(false);

      setVideoTitle(newDetail.title || newTitle);
      setVideoCover(newDetail.poster);
      setCurrentSource(newSource);
      setCurrentId(newId);
      setDetail(newDetail);
      setCurrentEpisodeIndex(targetIndex);
    } catch (err) {
      setError(err instanceof Error ? err.message : '换源失败');
    } finally {
      setSourceChanging(false);
    }
  };

  // 处理播放源面板展开
  const handleSourcePanelOpen = () => {
    setShowSourcePanel(true);
    playerContainerRef.current?.focus();
    // 只在第一次展开时搜索
    if (videoTitle && !hasSearchedRef.current) {
      handleSearch(videoTitle);
      hasSearchedRef.current = true;
    }
  };

  // 显示快捷键提示
  const displayShortcutHint = (text: string, direction: string) => {
    setShortcutText(text);
    setShortcutDirection(direction);
    setShowShortcutHint(true);

    // 清除之前的超时
    if (shortcutHintTimeoutRef.current) {
      clearTimeout(shortcutHintTimeoutRef.current);
    }

    // 2秒后隐藏
    shortcutHintTimeoutRef.current = setTimeout(() => {
      setShowShortcutHint(false);
    }, 2000);
  };

  // 处理全局快捷键
  const handleKeyboardShortcuts = (e: KeyboardEvent) => {
    // 忽略输入框中的按键事件
    if (
      (e.target as HTMLElement).tagName === 'INPUT' ||
      (e.target as HTMLElement).tagName === 'TEXTAREA'
    )
      return;

    // Alt + 左箭头 = 上一集
    if (e.altKey && e.key === 'ArrowLeft') {
      if (detailRef.current && currentEpisodeIndexRef.current > 0) {
        handlePreviousEpisode();
        displayShortcutHint('上一集', 'left');
      } else {
        displayShortcutHint('已经是第一集了', 'error');
      }
      e.preventDefault();
    }

    // Alt + 右箭头 = 下一集
    if (e.altKey && e.key === 'ArrowRight') {
      const d = detailRef.current;
      const idx = currentEpisodeIndexRef.current;
      if (d && idx < d.episodes.length - 1) {
        handleNextEpisode();
        displayShortcutHint('下一集', 'right');
      } else {
        displayShortcutHint('已经是最后一集了', 'error');
      }
      e.preventDefault();
    }

    if (!playerRef.current) return;
    const player = playerRef.current;

    // 左箭头 = 快退
    if (!e.altKey && e.key === 'ArrowLeft') {
      if (player.currentTime > 5) {
        player.currentTime -= 10;
        displayShortcutHint('快退', 'left');
      }
      e.preventDefault();
    }

    // 右箭头 = 快进
    if (!e.altKey && e.key === 'ArrowRight') {
      if (player.currentTime < player.duration - 5) {
        player.currentTime += 10;
        displayShortcutHint('快进', 'right');
      }
      e.preventDefault();
    }

    // 上箭头 = 音量+
    if (e.key === 'ArrowUp') {
      if (player.volume < 1) {
        player.volume += 0.1;
        displayShortcutHint(`音量 ${Math.round(player.volume * 100)}`, 'up');
      } else {
        displayShortcutHint('音量 100', 'up');
      }
      e.preventDefault();
    }

    // 下箭头 = 音量-
    if (e.key === 'ArrowDown') {
      if (player.volume > 0) {
        player.volume -= 0.1;
        displayShortcutHint(`音量 ${Math.round(player.volume * 100)}`, 'down');
      } else {
        displayShortcutHint('音量 0', 'down');
      }
      e.preventDefault();
    }

    // 空格 = 播放/暂停
    if (e.key === ' ') {
      if (playerRef.current.paused) {
        playerRef.current.play();
        displayShortcutHint('播放', 'play');
      } else {
        playerRef.current.pause();
        displayShortcutHint('暂停', 'pause');
      }
      e.preventDefault();
    }

    // f 键 = 切换全屏
    if (e.key === 'f' || e.key === 'F') {
      if (player.state.fullscreen) {
        player.exitFullscreen();
      } else {
        player.enterFullscreen();
      }
      e.preventDefault();
    }
  };

  // 保存播放进度的函数
  const saveCurrentPlayProgress = async () => {
    if (
      !playerRef.current ||
      !currentSourceRef.current ||
      !currentIdRef.current ||
      !videoTitleRef.current ||
      !detailRef.current?.source_name
    ) {
      return;
    }

    const player = playerRef.current;
    const currentTime = player.currentTime || 0;
    const duration = player.duration || 0;

    // 如果播放时间太短（少于5秒）或者视频时长无效，不保存
    if (currentTime < 1 || !duration) {
      return;
    }

    try {
      await savePlayRecord(currentSourceRef.current, currentIdRef.current, {
        title: videoTitleRef.current,
        source_name: detailRef.current?.source_name,
        cover: videoCover,
        year: detailRef.current?.year || videoYear || '',
        index: currentEpisodeIndexRef.current + 1, // 转换为1基索引
        total_episodes: totalEpisodes,
        play_time: Math.floor(currentTime),
        total_time: Math.floor(duration),
        save_time: Date.now(),
      });

      lastSaveTimeRef.current = Date.now();
      console.log('播放进度已保存:', {
        title: videoTitleRef.current,
        episode: currentEpisodeIndexRef.current + 1,
        progress: `${Math.floor(currentTime)}/${Math.floor(duration)}`,
      });
    } catch (err) {
      console.error('保存播放进度失败:', err);
    }
  };

  // 每当 source 或 id 变化时检查收藏状态
  useEffect(() => {
    if (!currentSource || !currentId) return;
    (async () => {
      try {
        const fav = await isFavorited(currentSource, currentId);
        setFavorited(fav);
      } catch (err) {
        console.error('检查收藏状态失败:', err);
      }
    })();
  }, [currentSource, currentId]);

  // 切换收藏
  const handleToggleFavorite = async () => {
    if (!currentSource || !currentId) return;

    try {
      const newState = await toggleFavorite(currentSource, currentId, {
        title: videoTitle,
        source_name: detail?.source_name || '',
        year: detail?.year || videoYear || '',
        cover: videoCover || '',
        total_episodes: totalEpisodes || 1,
        save_time: Date.now(),
      });
      setFavorited(newState);
    } catch (err) {
      console.error('切换收藏失败:', err);
    }
  };

  // 监听屏幕方向变化：竖屏时显示提示蒙层
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const mql = window.matchMedia('(orientation: portrait)');

    const update = () => {
      const portrait = mql.matches;

      // 更新竖屏状态
      setIsPortrait(portrait);

      // 在进入竖屏时显示提示，5 秒后自动隐藏
      if (portrait) {
        setShowOrientationTip(true);
        if (orientationTipTimeoutRef.current) {
          clearTimeout(orientationTipTimeoutRef.current);
        }
        orientationTipTimeoutRef.current = setTimeout(() => {
          setShowOrientationTip(false);
        }, 5000);
      } else {
        setShowOrientationTip(false);
        if (orientationTipTimeoutRef.current) {
          clearTimeout(orientationTipTimeoutRef.current);
          orientationTipTimeoutRef.current = null;
        }
      }
    };

    // 初始执行一次
    update();

    if (mql.addEventListener) {
      mql.addEventListener('change', update);
    } else {
      // Safari < 14
      // @ts-ignore
      mql.addListener(update);
    }

    return () => {
      if (mql.removeEventListener) {
        mql.removeEventListener('change', update);
      } else {
        // @ts-ignore
        mql.removeListener(update);
      }
    };
  }, []);

  // 用户点击悬浮按钮 -> 请求全屏并锁定横屏
  const handleForceLandscape = async () => {
    try {
      const el: any = document.documentElement;
      if (el.requestFullscreen) {
        await el.requestFullscreen();
      } else if (el.webkitRequestFullscreen) {
        el.webkitRequestFullscreen();
      }

      if (screen.orientation && (screen.orientation as any).lock) {
        await (screen.orientation as any).lock('landscape');
      }
    } catch (err) {
      console.warn('强制横屏失败:', err);
    }
  };

  // 进入/退出全屏时锁定/解锁横屏（保持原有逻辑）
  useEffect(() => {
    if (typeof document === 'undefined') return;

    const lockLandscape = async () => {
      try {
        // 某些浏览器需要在用户手势触发后才能调用
        if (screen.orientation && (screen.orientation as any).lock) {
          await (screen.orientation as any).lock('landscape');
        }
      } catch (err) {
        console.warn('横屏锁定失败:', err);
      }
    };

    const unlock = () => {
      try {
        if (screen.orientation && (screen.orientation as any).unlock) {
          (screen.orientation as any).unlock();
        }
      } catch (_) {
        // 忽略解锁屏幕方向失败的错误
      }
    };

    const player = playerRef.current;
    if (!player) return;

    return player.subscribe(({ fullscreen }: any) => {
      setIsFullscreen(fullscreen);
      if (fullscreen) {
        lockLandscape();
      } else {
        unlock();
        // 强制重绘逻辑，解决退出全屏的黑屏/白边问题
        const playerEl = playerRef.current?.el as HTMLElement | null;
        if (playerEl) {
          playerEl.style.display = 'none';
          setTimeout(() => {
            playerEl.style.display = '';
            setVH();
          }, 0);
        }
      }
    });
  }, [playerRef.current, setVH]);

  useEffect(() => {
    // 播放页挂载时，锁定页面滚动并消除 body 100vh 带来的额外空白
    if (typeof document === 'undefined') return;

    const { style: bodyStyle } = document.body;
    const { style: htmlStyle } = document.documentElement;

    // 记录原始样式，供卸载时恢复
    const originalBodyMinH = bodyStyle.minHeight;
    const originalBodyH = bodyStyle.height;
    const originalBodyOverflow = bodyStyle.overflow;
    const originalHtmlOverflow = htmlStyle.overflow;

    bodyStyle.minHeight = '0';
    bodyStyle.height = 'auto';
    bodyStyle.overflow = 'hidden';
    htmlStyle.overflow = 'hidden';

    return () => {
      bodyStyle.minHeight = originalBodyMinH;
      bodyStyle.height = originalBodyH;
      bodyStyle.overflow = originalBodyOverflow;
      htmlStyle.overflow = originalHtmlOverflow;
    };
  }, []);

  // 长按三倍速处理函数
  const handleTouchStart = (e: TouchEvent) => {
    // 防止在控制栏区域触发
    const target = e.target as HTMLElement;
    if (
      target.closest('.vds-controls') ||
      target.closest('.vds-context-menu') ||
      target.closest('.vds-lazy-gesture')
    ) {
      return;
    }

    // 仅在播放时触发
    if (!playerRef.current?.playing) {
      return;
    }

    // 清除之前的定时器
    if (longPressTimeoutRef.current) {
      clearTimeout(longPressTimeoutRef.current);
    }

    // 设置长按检测定时器（500ms）
    longPressTimeoutRef.current = setTimeout(() => {
      if (playerRef.current) {
        // 保存原始播放速度
        originalPlaybackRateRef.current = playerRef.current.playbackRate;

        // 设置三倍速
        playerRef.current.playbackRate = 3;

        // 更新状态
        setIsLongPressing(true);
        setShowSpeedTip(true);

        // 触发震动反馈（如果支持）
        if (navigator.vibrate) {
          navigator.vibrate(50);
        }

        // 3秒后自动隐藏提示
        if (speedTipTimeoutRef.current) {
          clearTimeout(speedTipTimeoutRef.current);
        }
        speedTipTimeoutRef.current = setTimeout(() => {
          setShowSpeedTip(false);
        }, 3000);
      }
    }, 500);
  };

  const handleTouchEnd = () => {
    // 清除长按检测定时器
    if (longPressTimeoutRef.current) {
      clearTimeout(longPressTimeoutRef.current);
      longPressTimeoutRef.current = null;
    }

    // 如果正在长按，恢复原始播放速度
    if (isLongPressing && playerRef.current) {
      playerRef.current.playbackRate = originalPlaybackRateRef.current;
      setIsLongPressing(false);
      setShowSpeedTip(false);

      // 清除提示定时器
      if (speedTipTimeoutRef.current) {
        clearTimeout(speedTipTimeoutRef.current);
        speedTipTimeoutRef.current = null;
      }
    }
  };

  // 添加触摸事件监听器
  useEffect(() => {
    const playerEl = playerRef.current?.el;
    if (!playerEl) return;

    const disableContextMenu = (e: Event) => {
      e.preventDefault();
      e.stopPropagation();
    };

    playerEl.addEventListener('touchstart', handleTouchStart, {
      passive: true,
    });
    playerEl.addEventListener('touchend', handleTouchEnd, { passive: true });
    playerEl.addEventListener('touchcancel', handleTouchEnd, { passive: true });
    playerEl.addEventListener('contextmenu', disableContextMenu);

    return () => {
      playerEl.removeEventListener('touchstart', handleTouchStart);
      playerEl.removeEventListener('touchend', handleTouchEnd);
      playerEl.removeEventListener('touchcancel', handleTouchEnd);
      playerEl.removeEventListener('contextmenu', disableContextMenu);
    };
  }, [playerRef.current, isLongPressing]);

  /* -------------------- 设置 meta theme-color 为纯黑 -------------------- */
  useEffect(() => {
    if (typeof document === 'undefined') return;

    // 查找或创建 meta[name="theme-color"]
    let metaTag = document.querySelector(
      'meta[name="theme-color"]'
    ) as HTMLMetaElement | null;

    if (!metaTag) {
      metaTag = document.createElement('meta');
      metaTag.setAttribute('name', 'theme-color');
      document.head.appendChild(metaTag);
    }

    // 记录原始颜色，并设置为纯黑
    metaTag.setAttribute('content', '#000000');

    // 卸载时恢复
    return () => {
      metaTag?.setAttribute('content', '#e6f3fb');
    };
  }, []);

  if (loading) {
    return (
      <div className='min-h-[100dvh] bg-black flex items-center justify-center overflow-hidden overscroll-contain'>
        <div className='text-white text-center'>
          <div className='animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500 mx-auto mb-4'></div>
          <div className='text-lg'>加载中...</div>
        </div>
      </div>
    );
  }

  if (error) {
    return (
      <div className='min-h-[100dvh] bg-black flex items-center justify-center overflow-hidden overscroll-contain'>
        <div className='text-white text-center'>
          <div className='text-xl font-semibold mb-4 text-red-400'>
            播放失败
          </div>
          <div className='text-base mb-6'>{error}</div>
          <button
            onClick={() => window.history.back()}
            className='px-6 py-2 bg-blue-500 hover:bg-blue-600 rounded-lg transition-colors'
          >
            返回
          </button>
        </div>
      </div>
    );
  }

  if (!detail) {
    return (
      <div className='min-h-[100dvh] bg-black flex items-center justify-center overflow-hidden overscroll-contain'>
        <div className='text-white text-center'>
          <div className='text-xl font-semibold mb-4'>未找到视频</div>
          <button
            onClick={() => window.history.back()}
            className='px-6 py-2 bg-blue-500 hover:bg-blue-600 rounded-lg transition-colors'
          >
            返回
          </button>
        </div>
      </div>
    );
  }

  const PlayerUITopbar = ({
    videoTitle,
    favorited,
    totalEpisodes,
    currentEpisodeIndex,
    sourceName,
    onToggleFavorite,
    onOpenSourcePanel,
    isFullscreen,
  }: {
    videoTitle: string;
    favorited: boolean;
    totalEpisodes: number;
    currentEpisodeIndex: number;
    sourceName: string;
    onToggleFavorite: () => void;
    onOpenSourcePanel: () => void;
    isFullscreen: boolean;
  }) => {
    return (
      <div
        data-top-bar
        className='absolute top-0 left-0 right-0 transition-opacity duration-300 z-10 opacity-0 pointer-events-none group-data-[controls]:opacity-100 group-data-[controls]:pointer-events-auto'
      >
        <div className='bg-black/60 backdrop-blur-sm px-0 sm:px-6 py-4 relative flex items-center sm:justify-center'>
          {/* 返回按钮 */}
          {!isFullscreen && (
            <button
              onClick={() => {
                if (playerRef.current?.fullscreen) {
                  playerRef.current?.exitFullscreen();
                }
                window.history.back();
              }}
              className='absolute left-0 sm:left-6 text-white hover:text-gray-300 transition-colors p-2'
            >
              <svg
                width='24'
                height='24'
                viewBox='0 0 24 24'
                fill='none'
                xmlns='http://www.w3.org/2000/svg'
              >
                <path
                  d='M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z'
                  fill='currentColor'
                />
              </svg>
            </button>
          )}

          {/* 中央标题及集数信息 */}
          <div
            className={`sm:text-center ${
              !isFullscreen ? 'ml-10 sm:ml-0 text-left' : 'w-full text-center'
            }`}
          >
            <div className='flex items-center justify-center gap-2 max-w-xs mx-auto'>
              <span className='text-white font-semibold text-lg truncate'>
                {videoTitle}
              </span>
              <button
                onClick={(e) => {
                  e.stopPropagation();
                  onToggleFavorite();
                }}
                className='flex-shrink-0'
              >
                <FavoriteIcon filled={favorited} />
              </button>
            </div>

            {totalEpisodes > 1 && (
              <div className='text-gray-300 text-sm mt-0.5'>
                第 {currentEpisodeIndex + 1} 集 / 共 {totalEpisodes} 集
              </div>
            )}
          </div>

          {/* 数据源徽章放置在右侧，不影响标题居中 */}
          {sourceName && (
            <span
              className='absolute right-2 sm:right-6 text-gray-300 text-sm border border-gray-500/60 px-2 py-[1px] rounded cursor-pointer hover:bg-gray-600/30 transition-colors'
              onClick={onOpenSourcePanel}
            >
              {sourceName}
            </span>
          )}
        </div>
      </div>
    );
  };

  const onProviderChange = (provider: MediaProviderAdapter | null) => {
    class extendedHls extends Hls {
      attachMedia(media: HTMLMediaElement): void {
        super.attachMedia(media);

        media.disableRemotePlayback = false;
        media.autoplay = true;
      }
    }
    if (isHLSProvider(provider)) {
      provider.library = extendedHls;
    }
  };

  return (
    <div
      ref={playerContainerRef}
      tabIndex={-1}
      className='bg-black fixed inset-0 overflow-hidden overscroll-contain'
      style={{ height: 'calc(var(--vh, 1vh) * 100)' }}
    >
      {/* 竖屏提示蒙层 */}
      {showOrientationTip && (
        <div className='fixed bottom-16 left-1/2 -translate-x-1/2 z-[190] flex items-center px-4 py-2 rounded bg-black/70 text-white space-x-2 pointer-events-none backdrop-blur-sm'>
          <svg
            className='w-5 h-5'
            fill='none'
            stroke='currentColor'
            viewBox='0 0 24 24'
          >
            <path
              strokeLinecap='round'
              strokeLinejoin='round'
              strokeWidth={2}
              d='M12 4v16m8-8H4'
            />
          </svg>
          <span className='text-sm'>请横屏观看</span>
        </div>
      )}

      {/* 强制横屏按钮：仅在移动端竖屏时显示 */}
      {isPortrait && (
        <button
          onClick={handleForceLandscape}
          className='fixed bottom-16 left-4 z-[85] w-10 h-10 rounded-full bg-gray-800 text-white flex items-center justify-center md:hidden'
        >
          <svg
            className='w-6 h-6'
            fill='none'
            stroke='currentColor'
            viewBox='0 0 24 24'
          >
            <path
              strokeLinecap='round'
              strokeLinejoin='round'
              strokeWidth={2}
              d='M3 18v-6a3 3 0 013-3h12M21 6v6a3 3 0 01-3 3H6'
            />
          </svg>
        </button>
      )}

      {/* 换源加载遮罩 */}
      {sourceChanging && (
        <div className='fixed inset-0 bg-black/50 z-[200] flex items-center justify-center'>
          <div className='text-white text-center'>
            <div className='animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-blue-500 mx-auto mb-2'></div>
            <div className='text-sm'>换源中...</div>
          </div>
        </div>
      )}

      {/* 播放器容器 */}
      <MediaPlayer
        ref={playerRef}
        className='w-full h-full group'
        src={videoUrl}
        poster={videoCover}
        playsInline
        autoPlay
        crossOrigin='anonymous'
        controlsDelay={3000}
        keyDisabled
        onCanPlay={onCanPlay}
        onEnded={onEnded}
        onTimeUpdate={onTimeUpdate}
        onPause={saveCurrentPlayProgress}
        onError={handlePlayerError}
        onProviderChange={onProviderChange}
      >
        <MediaProvider />
        <PlayerUITopbar
          videoTitle={videoTitle}
          favorited={favorited}
          totalEpisodes={totalEpisodes}
          currentEpisodeIndex={currentEpisodeIndex}
          sourceName={detail?.source_name || ''}
          onToggleFavorite={handleToggleFavorite}
          onOpenSourcePanel={handleSourcePanelOpen}
          isFullscreen={isFullscreen}
        />
        <DefaultVideoLayout
          icons={defaultLayoutIcons}
          slots={{
            googleCastButton: null,
            pipButton: null,
            settingsMenu: null,
            muteButton: null, // 隐藏静音按钮
            volumeSlider: null, // 隐藏音量条
            airPlayButton: null, // 隐藏默认 AirPlay 按钮
            beforeCurrentTime:
              totalEpisodes > 1 ? (
                // 下一集按钮放在时间显示前
                <button
                  className='vds-button mr-2'
                  onClick={handleNextEpisode}
                  aria-label='Next Episode'
                >
                  <svg
                    className='vds-icon'
                    viewBox='0 0 32 32'
                    xmlns='http://www.w3.org/2000/svg'
                  >
                    <path
                      d='M6 24l12-8L6 8v16zM22 8v16h3V8h-3z'
                      fill='currentColor'
                    />
                  </svg>
                </button>
              ) : null,
            beforeFullscreenButton: (
              <>
                {totalEpisodes > 1 && (
                  <button
                    className='vds-button mr-2'
                    onClick={() => {
                      setShowEpisodePanel(true);
                      playerContainerRef.current?.focus();
                    }}
                  >
                    选集
                  </button>
                )}
                <PlaybackRateButton playerRef={playerRef} />
                {/* 自定义 AirPlay 按钮 */}
                <AirPlayButton className='vds-button'>
                  <AirPlayIcon className='vds-icon' />
                </AirPlayButton>
              </>
            ),
          }}
        />

        {/* 选集侧拉面板 */}
        {totalEpisodes > 1 && (
          <div data-episode-panel>
            {/* 遮罩层 */}
            {showEpisodePanel && (
              <div
                className='fixed inset-0 bg-black/50 z-[110]'
                onClick={() => {
                  setShowEpisodePanel(false);
                  playerContainerRef.current?.focus();
                }}
              />
            )}

            {/* 侧拉面板 */}
            <div
              className={`fixed top-0 right-0 h-full w-full mobile-landscape:w-1/2 md:w-80 bg-black/40 backdrop-blur-xl z-[110] transform transition-transform duration-300 ${
                showEpisodePanel ? 'translate-x-0' : 'translate-x-full'
              }`}
            >
              <div className='p-6 h-full flex flex-col'>
                <div className='flex items-center justify-between mb-6'>
                  <h3 className='text-white text-xl font-semibold'>选集列表</h3>
                  <button
                    onClick={() => {
                      setShowEpisodePanel(false);
                      playerContainerRef.current?.focus();
                    }}
                    className='text-gray-400 hover:text-white transition-colors'
                  >
                    <svg
                      className='w-6 h-6'
                      fill='none'
                      stroke='currentColor'
                      viewBox='0 0 24 24'
                    >
                      <path
                        strokeLinecap='round'
                        strokeLinejoin='round'
                        strokeWidth={2}
                        d='M6 18L18 6M6 6l12 12'
                      />
                    </svg>
                  </button>
                </div>

                <div className='text-gray-300 text-sm mb-4'>
                  当前: 第 {currentEpisodeIndex + 1} 集 / 共 {totalEpisodes} 集
                </div>

                <div className='flex-1 overflow-y-auto'>
                  <div className='grid grid-cols-4 gap-3'>
                    {Array.from({ length: totalEpisodes }, (_, idx) => (
                      <button
                        key={idx}
                        onClick={() => handleEpisodeChange(idx)}
                        className={`px-3 py-2 text-sm rounded-lg transition-colors ${
                          idx === currentEpisodeIndex
                            ? 'bg-green-500 text-white'
                            : 'bg-gray-700 text-gray-300 hover:bg-gray-600'
                        }`}
                      >
                        {idx + 1}
                      </button>
                    ))}
                  </div>
                </div>
              </div>
            </div>
          </div>
        )}

        {/* 换源侧拉面板 */}
        <div data-source-panel>
          {/* 遮罩层 */}
          {showSourcePanel && (
            <div
              className='fixed inset-0 bg-black/50 z-[110]'
              onClick={() => {
                setShowSourcePanel(false);
                playerContainerRef.current?.focus();
              }}
            />
          )}

          {/* 侧拉面板 */}
          <div
            className={`fixed top-0 right-0 h-full w-full mobile-landscape:w-1/2 md:w-96 bg-black/40 backdrop-blur-xl z-[110] transform transition-transform duration-300 ${
              showSourcePanel ? 'translate-x-0' : 'translate-x-full'
            }`}
          >
            <div className='p-6 h-full flex flex-col'>
              <div className='flex items-center justify-between mb-6'>
                <h3 className='text-white text-xl font-semibold'>播放源</h3>
                <button
                  onClick={() => {
                    setShowSourcePanel(false);
                    playerContainerRef.current?.focus();
                  }}
                  className='text-gray-400 hover:text-white transition-colors'
                >
                  <svg
                    className='w-6 h-6'
                    fill='none'
                    stroke='currentColor'
                    viewBox='0 0 24 24'
                  >
                    <path
                      strokeLinecap='round'
                      strokeLinejoin='round'
                      strokeWidth={2}
                      d='M6 18L18 6M6 6l12 12'
                    />
                  </svg>
                </button>
              </div>

              {/* 搜索结果 */}
              <div className='flex-1 overflow-y-auto'>
                {searchLoading && (
                  <div className='flex items-center justify-center py-8'>
                    <div className='animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-blue-500'></div>
                    <span className='text-gray-300 ml-3'>搜索中...</span>
                  </div>
                )}

                {searchError && (
                  <div className='text-red-400 text-center py-4'>
                    {searchError}
                  </div>
                )}

                {!searchLoading &&
                  !searchError &&
                  searchResults.length === 0 && (
                    <div className='text-gray-400 text-center py-8'>
                      未找到相关视频源
                    </div>
                  )}

                {!searchLoading && !searchError && searchResults.length > 0 && (
                  <div className='grid grid-cols-2 gap-4'>
                    {[
                      ...searchResults.filter(
                        (r) =>
                          r.source === currentSource &&
                          String(r.id) === String(currentId)
                      ),
                      ...searchResults.filter(
                        (r) =>
                          !(
                            r.source === currentSource &&
                            String(r.id) === String(currentId)
                          )
                      ),
                    ].map((result) => {
                      const isCurrentSource =
                        result.source === currentSource &&
                        String(result.id) === String(currentId);
                      return (
                        <div
                          key={`${result.source}-${result.id}`}
                          className={`rounded-lg transition-colors border-2 ${
                            isCurrentSource
                              ? 'border-green-500 bg-green-500/20 cursor-not-allowed opacity-60'
                              : 'border-transparent bg-transparent hover:bg-gray-600/30 cursor-pointer'
                          }`}
                          onClick={() =>
                            !isCurrentSource &&
                            handleSourceChange(
                              result.source,
                              result.id,
                              result.title
                            )
                          }
                        >
                          {/* 视频封面 */}
                          <div className='aspect-[2/3] rounded-t-lg overflow-hidden flex items-center justify-center p-1 relative'>
                            <img
                              src={result.poster}
                              alt={result.title}
                              className='w-full h-full object-cover rounded'
                              referrerPolicy='no-referrer'
                            />

                            {/* 集数圆形指示器 */}
                            {result.episodes && (
                              <div className='absolute top-2 right-2 w-6 h-6 bg-green-500 rounded-full flex items-center justify-center'>
                                <span className='text-white text-xs font-bold'>
                                  {result.episodes.length}
                                </span>
                              </div>
                            )}

                            {isCurrentSource && (
                              <div className='absolute inset-0 flex items-center justify-center pointer-events-none'>
                                <div className='bg-green-500 text-white text-xs px-3 py-1 rounded shadow-lg'>
                                  当前播放
                                </div>
                              </div>
                            )}
                          </div>

                          {/* 视频信息 */}
                          <div className='p-2 bg-transparent text-center'>
                            <h4 className='text-white font-medium text-sm line-clamp-2 mb-2 leading-tight'>
                              {result.title}
                            </h4>
                            <div className='text-gray-400 text-xs space-y-1'>
                              <div className='inline-block border border-gray-500/60 rounded px-2 py-[1px]'>
                                {result.source_name}
                              </div>
                            </div>
                          </div>
                        </div>
                      );
                    })}
                  </div>
                )}
              </div>
            </div>
          </div>
        </div>

        {/* 快捷键提示 */}
        <div
          className={`absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-50 transition-opacity duration-300 ${
            showShortcutHint ? 'opacity-100' : 'opacity-0 pointer-events-none'
          }`}
        >
          <div className='bg-black/80 backdrop-blur-sm rounded p-4 flex items-center space-x-3'>
            <svg
              className='w-6 h-6 text-white'
              fill='none'
              stroke='currentColor'
              viewBox='0 0 24 24'
            >
              {shortcutDirection === 'left' && (
                <path
                  strokeLinecap='round'
                  strokeLinejoin='round'
                  strokeWidth='2'
                  d='M15 19l-7-7 7-7'
                ></path>
              )}
              {shortcutDirection === 'right' && (
                <path
                  strokeLinecap='round'
                  strokeLinejoin='round'
                  strokeWidth='2'
                  d='M9 5l7 7-7 7'
                ></path>
              )}
              {shortcutDirection === 'up' && (
                <path
                  strokeLinecap='round'
                  strokeLinejoin='round'
                  strokeWidth='2'
                  d='M5 15l7-7 7 7'
                ></path>
              )}
              {shortcutDirection === 'down' && (
                <path
                  strokeLinecap='round'
                  strokeLinejoin='round'
                  strokeWidth='2'
                  d='M19 9l-7 7-7-7'
                ></path>
              )}
              {shortcutDirection === 'play' && (
                <path
                  strokeLinecap='round'
                  strokeLinejoin='round'
                  strokeWidth='2'
                  d='M8 5v14l11-7L8 5z'
                ></path>
              )}
              {shortcutDirection === 'pause' && (
                <path
                  strokeLinecap='round'
                  strokeLinejoin='round'
                  strokeWidth='2'
                  d='M6 6h4v12H6zm8 0h4v12h-4z'
                ></path>
              )}
              {shortcutDirection === 'error' && (
                <path
                  strokeLinecap='round'
                  strokeLinejoin='round'
                  strokeWidth='2'
                  d='M6 18L18 6M6 6l12 12'
                ></path>
              )}
            </svg>
            <span className='text-white font-medium'>{shortcutText}</span>
          </div>
        </div>

        {/* 三倍速提示 */}
        <div
          className={`absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-50 transition-opacity duration-300 ${
            showSpeedTip ? 'opacity-100' : 'opacity-0 pointer-events-none'
          }`}
        >
          <div className='bg-black/60 backdrop-blur-sm rounded-lg p-4 flex items-center space-x-3'>
            <svg
              className='w-6 h-6 text-white animate-pulse'
              fill='none'
              stroke='currentColor'
              viewBox='0 0 24 24'
            >
              <path
                strokeLinecap='round'
                strokeLinejoin='round'
                strokeWidth='2'
                d='M13 10V3L4 14h7v7l9-11h-7z'
              />
            </svg>
            <span className='text-white font-bold text-lg'>3x 倍速</span>
          </div>
        </div>
      </MediaPlayer>
    </div>
  );
}

const PlaybackRateButton = ({
  playerRef,
}: {
  playerRef: React.RefObject<any>;
}) => {
  const [rate, setRate] = useState(1);
  const rates = [0.75, 1.0, 1.25, 1.5, 2.0, 3.0];

  useEffect(() => {
    const player = playerRef.current;
    if (!player) return;
    // @ts-ignore
    const unsubscribe = player.subscribe(({ playbackRate }) => {
      setRate(playbackRate);
    });
    return unsubscribe;
  }, [playerRef]);

  const cycleRate = () => {
    const player = playerRef.current;
    if (!player) return;
    const currentIndex = rates.indexOf(rate);
    const nextIndex = (currentIndex + 1) % rates.length;
    player.playbackRate = rates[nextIndex];
  };

  return (
    <button className='vds-button mr-2' onClick={cycleRate}>
      {rate === 1 ? '倍速' : `${rate.toFixed(2)}x`}
    </button>
  );
};

const FavoriteIcon = ({ filled }: { filled: boolean }) => {
  if (filled) {
    return (
      <svg
        className='h-5 w-5'
        viewBox='0 0 24 24'
        xmlns='http://www.w3.org/2000/svg'
      >
        <path
          d='M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z'
          fill='#ef4444' /* Tailwind red-500 */
          stroke='#ef4444'
          strokeWidth='2'
          strokeLinecap='round'
          strokeLinejoin='round'
        />
      </svg>
    );
  }
  return <Heart className='h-5 w-5 stroke-[2] text-gray-300' />;
};

export default function PlayPage() {
  return (
    <Suspense>
      <PlayPageClient />
    </Suspense>
  );
}
