'use client';

import {
  Calendar,
  Clock,
  ExternalLink,
  Film,
  Globe,
  Images,
  Star,
  Tag,
  Users,
  X,
} from 'lucide-react';
import Image from 'next/image';
import React, { useEffect, useState } from 'react';
import { createPortal } from 'react-dom';

import { getBangumiSubject, getBangumiSubjectUrl } from '@/lib/bangumi.client';
import { appendSpecialSourceParam } from '@/lib/special-source.client';
import { getTMDBImageUrl } from '@/lib/tmdb.client';
import { processImageUrl } from '@/lib/utils';

import ImageViewer from '@/components/ImageViewer';
import ProxyImage from '@/components/ProxyImage';

interface DetailPanelProps {
  isOpen: boolean;
  onClose: () => void;
  title: string;
  poster?: string;
  doubanId?: number;
  bangumiId?: number;
  isBangumi?: boolean;
  tmdbId?: number;
  type?: 'movie' | 'tv';
  seasonNumber?: number;
  currentEpisode?: number;
  cmsData?: {
    desc?: string;
    episodes?: string[];
    episodes_titles?: string[];
  };
  sourceId?: string;
  source?: string;
  useDrawer?: boolean;
  drawerWidth?: string;
}

interface DetailData {
  title: string;
  originalTitle?: string;
  year?: string;
  poster?: string;
  rating?: {
    value: number;
    count: number;
  };
  intro?: string;
  genres?: string[];
  directors?: Array<{ name: string; profile_path?: string }>;
  actors?: Array<{ name: string; character?: string; profile_path?: string }>;
  countries?: string[];
  languages?: string[];
  duration?: string;
  episodesCount?: number;
  releaseDate?: string;
  status?: string;
  tagline?: string;
  seasons?: number;
  overview?: string;
  tmdbId?: number;
  mediaType?: 'movie' | 'tv';
  seasonNumber?: number;
  seriesTitle?: string;
}

interface Episode {
  id: number;
  name: string;
  episode_number: number;
  still_path: string | null;
  overview: string;
  air_date: string;
}

interface GalleryImage {
  file_path: string;
  width: number;
  height: number;
  vote_average?: number;
  vote_count?: number;
  iso_639_1?: string | null;
  imageType: 'backdrop' | 'poster';
}

const DetailPanel: React.FC<DetailPanelProps> = ({
  isOpen,
  onClose,
  title,
  poster,
  doubanId,
  bangumiId,
  isBangumi,
  tmdbId,
  type = 'movie',
  seasonNumber,
  currentEpisode,
  cmsData,
  sourceId,
  source,
  useDrawer = false,
  drawerWidth = 'w-full md:w-[25%]',
}) => {
  const [isVisible, setIsVisible] = useState(false);
  const [isAnimating, setIsAnimating] = useState(false);
  const [mounted, setMounted] = useState(false);
  const [detailData, setDetailData] = useState<DetailData | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [seasonData, setSeasonData] = useState<{
    seasons: any[];
    episodes: Episode[];
  } | null>(null);
  const [loadingSeasons, setLoadingSeasons] = useState(false);
  const [expandedEpisodes, setExpandedEpisodes] = useState<Set<number>>(
    new Set()
  );
  const [selectedSeason, setSelectedSeason] = useState<number>(1);
  const [seasonsLoaded, setSeasonsLoaded] = useState(false);
  const [showImageViewer, setShowImageViewer] = useState(false);
  const [selectedImage, setSelectedImage] = useState<string>('');
  const [showGallery, setShowGallery] = useState(false);
  const [galleryLoading, setGalleryLoading] = useState(false);
  const [galleryError, setGalleryError] = useState<string | null>(null);
  const [galleryImages, setGalleryImages] = useState<GalleryImage[]>([]);
  const [galleryTotal, setGalleryTotal] = useState(0);
  const [galleryScrollTop, setGalleryScrollTop] = useState(0);
  const [galleryViewportHeight, setGalleryViewportHeight] = useState(0);
  const [galleryViewportWidth, setGalleryViewportWidth] = useState(0);
  const galleryScrollRef = React.useRef<HTMLDivElement>(null);

  // 数据源状态管理
  const [currentSource, setCurrentSource] = useState<
    'douban' | 'bangumi' | 'cms' | 'tmdb'
  >('tmdb');
  const [originalSource, setOriginalSource] = useState<
    'douban' | 'bangumi' | 'cms' | 'tmdb'
  >('tmdb');
  const [isUsingTmdb, setIsUsingTmdb] = useState(false);
  const [originalDetailData, setOriginalDetailData] =
    useState<DetailData | null>(null);

  const getExternalUrl = () => {
    if (currentSource === 'douban' && doubanId) {
      return `https://movie.douban.com/subject/${doubanId}`;
    }

    if (currentSource === 'bangumi') {
      const actualBangumiId = bangumiId || doubanId;
      if (actualBangumiId) {
        return getBangumiSubjectUrl(actualBangumiId);
      }
    }

    if (currentSource === 'tmdb') {
      const actualTmdbId = detailData?.tmdbId || tmdbId;
      const actualMediaType = detailData?.mediaType || type;
      if (actualTmdbId) {
        return `https://www.themoviedb.org/${actualMediaType}/${actualTmdbId}`;
      }
    }

    return null;
  };

  const externalUrl = getExternalUrl();

  // 拖动滚动状态
  const [isDragging, setIsDragging] = useState(false);
  const [isMouseDown, setIsMouseDown] = useState(false);
  const [startX, setStartX] = useState(0);
  const [scrollLeft, setScrollLeft] = useState(0);
  const episodesScrollRef = React.useRef<HTMLDivElement>(null);
  const actorsScrollRef = React.useRef<HTMLDivElement>(null);
  const [isActorsDragging, setIsActorsDragging] = useState(false);
  const [isActorsMouseDown, setIsActorsMouseDown] = useState(false);
  const [actorsStartX, setActorsStartX] = useState(0);
  const [actorsScrollLeft, setActorsScrollLeft] = useState(0);

  // 图片点击处理
  const handleImageClick = (imageUrl: string) => {
    setSelectedImage(imageUrl);
    setShowImageViewer(true);
  };

  const galleryTmdbId = detailData?.tmdbId || tmdbId;
  const galleryMediaType = detailData?.mediaType || type;
  const canShowGalleryEntry = !!galleryTmdbId && !!galleryMediaType;

  const fetchGalleryImages = async () => {
    if (!galleryTmdbId || !galleryMediaType) return;

    setGalleryLoading(true);
    setGalleryError(null);

    try {
      const response = await fetch(
        `/api/tmdb/images?id=${galleryTmdbId}&type=${galleryMediaType}`
      );

      if (!response.ok) {
        throw new Error('获取照片墙失败');
      }

      const data = await response.json();
      setGalleryImages(data.list || []);
      setGalleryTotal(data.total || 0);
    } catch (err) {
      console.error('获取照片墙失败:', err);
      setGalleryError(err instanceof Error ? err.message : '获取照片墙失败');
    } finally {
      setGalleryLoading(false);
    }
  };

  const openGallery = () => {
    setShowGallery(true);
  };

  // 确保组件在客户端挂载后才渲染 Portal
  useEffect(() => {
    setMounted(true);
  }, []);

  useEffect(() => {
    if (!showGallery) {
      setGalleryImages([]);
      setGalleryError(null);
      setGalleryLoading(false);
      setGalleryTotal(0);
      setGalleryScrollTop(0);
      setGalleryViewportHeight(0);
      setGalleryViewportWidth(0);
      return;
    }

    fetchGalleryImages();
  }, [showGallery, galleryTmdbId, galleryMediaType]);

  useEffect(() => {
    if (!showGallery || !galleryScrollRef.current) return;

    const element = galleryScrollRef.current;

    const updateMetrics = () => {
      setGalleryViewportHeight(element.clientHeight);
      setGalleryViewportWidth(element.clientWidth);
      setGalleryScrollTop(element.scrollTop);
    };

    updateMetrics();
    element.addEventListener('scroll', updateMetrics, { passive: true });
    const resizeObserver = new ResizeObserver(updateMetrics);
    resizeObserver.observe(element);

    return () => {
      element.removeEventListener('scroll', updateMetrics);
      resizeObserver.disconnect();
    };
  }, [showGallery]);

  // 控制动画状态
  useEffect(() => {
    let animationId: number;
    let timer: NodeJS.Timeout;

    if (isOpen) {
      setIsVisible(true);
      animationId = requestAnimationFrame(() => {
        animationId = requestAnimationFrame(() => {
          setIsAnimating(true);
        });
      });
    } else {
      setIsAnimating(false);
      timer = setTimeout(() => {
        setIsVisible(false);
      }, 200);
    }

    return () => {
      if (animationId) {
        cancelAnimationFrame(animationId);
      }
      if (timer) {
        clearTimeout(timer);
      }
    };
  }, [isOpen]);

  useEffect(() => {
    if (!isOpen) {
      setShowGallery(false);
    }
  }, [isOpen]);

  // 阻止背景滚动（仅在非抽屉模式下）
  useEffect(() => {
    if (isVisible && !useDrawer) {
      // 保存当前滚动位置
      const scrollY = window.scrollY;
      const scrollX = window.scrollX;
      const body = document.body;
      const html = document.documentElement;

      // 获取滚动条宽度
      const scrollBarWidth = window.innerWidth - html.clientWidth;

      // 保存原始样式
      const originalBodyStyle = {
        position: body.style.position,
        top: body.style.top,
        left: body.style.left,
        right: body.style.right,
        width: body.style.width,
        paddingRight: body.style.paddingRight,
        overflow: body.style.overflow,
      };

      // 设置body样式来阻止滚动，但保持原位置
      body.style.position = 'fixed';
      body.style.top = `-${scrollY}px`;
      body.style.left = `-${scrollX}px`;
      body.style.right = '0';
      body.style.width = '100%';
      body.style.overflow = 'hidden';
      body.style.paddingRight = `${scrollBarWidth}px`;

      return () => {
        // 恢复所有原始样式
        body.style.position = originalBodyStyle.position;
        body.style.top = originalBodyStyle.top;
        body.style.left = originalBodyStyle.left;
        body.style.right = originalBodyStyle.right;
        body.style.width = originalBodyStyle.width;
        body.style.paddingRight = originalBodyStyle.paddingRight;
        body.style.overflow = originalBodyStyle.overflow;

        // 使用 requestAnimationFrame 确保样式恢复后再滚动
        requestAnimationFrame(() => {
          window.scrollTo(scrollX, scrollY);
        });
      };
    }
  }, [isVisible, useDrawer]);

  // ESC键关闭
  useEffect(() => {
    const handleEsc = (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        onClose();
      }
    };

    if (isVisible) {
      document.addEventListener('keydown', handleEsc);
      return () => document.removeEventListener('keydown', handleEsc);
    }
  }, [isVisible, onClose]);

  // 获取详情数据
  useEffect(() => {
    if (!isOpen) {
      return;
    }

    const fetchDetail = async () => {
      setLoading(true);
      setError(null);

      try {
        // 如果正在使用 TMDB 数据，强制使用 TMDB
        if (isUsingTmdb && title) {
          await fetchTmdbData();
          return;
        }

        // 优先使用苹果CMS数据（短剧等）
        // 如果 cmsData 存在但 desc 为空，尝试通过 source-detail API 获取
        if (cmsData) {
          setCurrentSource('cms');
          setOriginalSource('cms');
          if (cmsData.desc) {
            // 有 desc，直接使用
            const data = {
              title: title,
              intro: cmsData.desc,
              episodesCount: cmsData.episodes?.length,
              poster: poster,
            };
            setDetailData(data);
            setOriginalDetailData(data);
            setLoading(false);
            return;
          }

          // cmsData 存在但 desc 为空，尝试通过 API 获取详情
          if (sourceId && source) {
            try {
              const response = await fetch(
                appendSpecialSourceParam(`/api/source-detail?id=${encodeURIComponent(
                  sourceId
                )}&source=${encodeURIComponent(
                  source
                )}&title=${encodeURIComponent(title)}`)
              );
              if (response.ok) {
                const data = await response.json();
                const detailData = {
                  title: data.title || title,
                  intro: data.desc || '',
                  episodesCount:
                    data.episodes?.length || cmsData.episodes?.length,
                  poster: data.poster || poster,
                  year: data.year,
                };
                setDetailData(detailData);
                setOriginalDetailData(detailData);
                setLoading(false);
                return;
              }
            } catch (err) {
              console.error('获取source-detail失败:', err);
              // 继续执行后续逻辑
            }
          }
        }

        // 优先使用 Bangumi ID（因为 isBangumi 为 true 时，doubanId 实际上是 bangumiId）
        if (bangumiId || (isBangumi && doubanId)) {
          setCurrentSource('bangumi');
          setOriginalSource('bangumi');
          const actualBangumiId = bangumiId || doubanId;
          if (!actualBangumiId) {
            throw new Error('Bangumi ID 缺失');
          }
          const data = await getBangumiSubject(actualBangumiId);

          const detailData = {
            title: data.name_cn || data.name,
            originalTitle: data.name,
            year: data.date ? data.date.substring(0, 4) : undefined,
            poster: data.images?.large || poster,
            rating: data.rating
              ? {
                  value: data.rating.score,
                  count: data.rating.total,
                }
              : undefined,
            intro: data.summary,
            genres: data.tags?.map((tag: any) => tag.name).slice(0, 5),
            episodesCount: data.eps,
            releaseDate: data.date,
          };
          setDetailData(detailData);
          setOriginalDetailData(detailData);
          return;
        }

        // 使用豆瓣ID
        if (doubanId && !isBangumi) {
          setCurrentSource('douban');
          setOriginalSource('douban');
          const response = await fetch(`/api/douban/detail?id=${doubanId}`);
          if (!response.ok) {
            throw new Error('获取豆瓣详情失败');
          }
          const data = await response.json();

          const detailData = {
            title: data.title,
            originalTitle: data.original_title,
            year: data.year,
            poster: data.pic?.large || data.pic?.normal || poster,
            rating: data.rating
              ? {
                  value: data.rating.value,
                  count: data.rating.count,
                }
              : undefined,
            intro: data.intro,
            genres: data.genres,
            directors: data.directors,
            actors: data.actors,
            countries: data.countries,
            languages: data.languages,
            duration: data.durations?.[0],
            episodesCount: data.episodes_count,
          };
          setDetailData(detailData);
          setOriginalDetailData(detailData);
          return;
        }

        // 使用 TMDB 搜索
        if (title) {
          setCurrentSource('tmdb');
          setOriginalSource('tmdb');
          await fetchTmdbData();
          return;
        }

        throw new Error('缺少必要的查询参数');
      } catch (err) {
        console.error('获取详情失败:', err);
        setError(err instanceof Error ? err.message : '获取详情失败');
      } finally {
        setLoading(false);
      }
    };

    // 提取 TMDB 数据获取逻辑为独立函数
    const fetchTmdbData = async () => {
      setCurrentSource('tmdb');
      // 移除季度信息进行搜索
      let searchTitle = title;
      let extractedSeasonNumber = seasonNumber;

      // 匹配各种季度格式: 第一季、第1季、第一部、Season 1、S1等
      const seasonPatterns = [
        /第([一二三四五六七八九十\d]+)[季部]/,
        /Season\s*(\d+)/i,
        /S(\d+)/i,
      ];

      for (const pattern of seasonPatterns) {
        const match = title.match(pattern);
        if (match) {
          searchTitle = title.replace(pattern, '').trim();
          // 如果没有传入seasonNumber,尝试从标题中提取
          if (!extractedSeasonNumber) {
            const seasonStr = match[1];
            // 中文数字转数字
            const chineseNumbers: Record<string, number> = {
              一: 1,
              二: 2,
              三: 3,
              四: 4,
              五: 5,
              六: 6,
              七: 7,
              八: 8,
              九: 9,
              十: 10,
            };
            extractedSeasonNumber =
              chineseNumbers[seasonStr] || parseInt(seasonStr) || undefined;
          }
          break;
        }
      }

      const searchResponse = await fetch(
        `/api/tmdb/search?query=${encodeURIComponent(searchTitle)}`
      );
      if (!searchResponse.ok) {
        throw new Error('搜索失败');
      }
      const searchData = await searchResponse.json();

      if (searchData.results && searchData.results.length > 0) {
        const result = searchData.results[0];
        const detailId = result.id;
        const mediaType = result.media_type || type;

        // 获取详情
        const detailResponse = await fetch(
          `/api/tmdb/detail?id=${detailId}&type=${mediaType}`
        );
        if (!detailResponse.ok) {
          throw new Error('获取TMDB详情失败');
        }
        const detailResult = await detailResponse.json();

        // 如果有季度信息,尝试获取季度详情
        let seasonData = null;
        if (extractedSeasonNumber && mediaType === 'tv') {
          try {
            const seasonResponse = await fetch(
              `/api/tmdb/episodes?id=${detailId}&season=${extractedSeasonNumber}`
            );
            if (seasonResponse.ok) {
              seasonData = await seasonResponse.json();
            }
          } catch (err) {
            console.error('获取季度信息失败', err);
          }
        }

        setDetailData({
          title:
            mediaType === 'movie'
              ? detailResult.title
              : seasonData?.name
              ? `${detailResult.name} ${seasonData.name}`
              : detailResult.name,
          originalTitle:
            mediaType === 'movie'
              ? detailResult.original_title
              : detailResult.original_name,
          year:
            mediaType === 'movie'
              ? detailResult.release_date?.substring(0, 4)
              : seasonData?.air_date?.substring(0, 4) ||
                detailResult.first_air_date?.substring(0, 4),
          poster:
            seasonData?.poster_path || detailResult.poster_path
              ? processImageUrl(
                  getTMDBImageUrl(
                    seasonData?.poster_path || detailResult.poster_path,
                    'w500'
                  )
                )
              : poster,
          rating: detailResult.vote_average
            ? {
                value: detailResult.vote_average,
                count: detailResult.vote_count,
              }
            : undefined,
          intro: seasonData?.overview || detailResult.overview,
          genres: detailResult.genres?.map((g: any) => g.name),
          countries: detailResult.production_countries?.map((c: any) => c.name),
          languages: detailResult.spoken_languages?.map((l: any) => l.name),
          duration: detailResult.runtime
            ? `${detailResult.runtime}分钟`
            : undefined,
          episodesCount:
            seasonData?.episodes?.length || detailResult.number_of_episodes,
          releaseDate:
            mediaType === 'movie'
              ? detailResult.release_date
              : seasonData?.air_date || detailResult.first_air_date,
          status: detailResult.status,
          tagline: detailResult.tagline,
          seasons: detailResult.number_of_seasons,
          overview: detailResult.overview,
          tmdbId: detailId,
          mediaType: mediaType,
          seasonNumber: extractedSeasonNumber,
          seriesTitle: mediaType === 'tv' ? detailResult.name : undefined,
        });
        return;
      }

      throw new Error('未找到相关内容');
    };

    fetchDetail();
  }, [
    isOpen,
    doubanId,
    bangumiId,
    isBangumi,
    tmdbId,
    title,
    type,
    seasonNumber,
    poster,
    cmsData,
    sourceId,
    source,
    isUsingTmdb,
  ]);

  // 切换数据源的函数
  const handleToggleSource = async () => {
    if (currentSource === 'tmdb') {
      // 切换回原始数据源
      if (originalDetailData) {
        setDetailData(originalDetailData);
        setCurrentSource(originalSource);
        setError(null);
      }
    } else {
      // 切换到 TMDB
      // 保存当前数据
      if (detailData && !originalDetailData) {
        setOriginalDetailData(detailData);
      }

      setLoading(true);
      setError(null);
      try {
        await fetchTmdbDataForToggle();
      } catch (err) {
        console.error('切换到TMDB失败:', err);
        setError(err instanceof Error ? err.message : '切换到TMDB失败');
        // 切换失败，但保持 currentSource 为 tmdb，这样可以显示切换回按钮
        setCurrentSource('tmdb');
      } finally {
        setLoading(false);
      }
    }
  };

  // 用于切换时获取 TMDB 数据
  const fetchTmdbDataForToggle = async () => {
    // 移除季度信息进行搜索
    let searchTitle = title;
    let extractedSeasonNumber = seasonNumber;

    // 匹配各种季度格式: 第一季、第1季、第一部、Season 1、S1等
    const seasonPatterns = [
      /第([一二三四五六七八九十\d]+)[季部]/,
      /Season\s*(\d+)/i,
      /S(\d+)/i,
    ];

    for (const pattern of seasonPatterns) {
      const match = title.match(pattern);
      if (match) {
        searchTitle = title.replace(pattern, '').trim();
        // 如果没有传入seasonNumber,尝试从标题中提取
        if (!extractedSeasonNumber) {
          const seasonStr = match[1];
          // 中文数字转数字
          const chineseNumbers: Record<string, number> = {
            一: 1,
            二: 2,
            三: 3,
            四: 4,
            五: 5,
            六: 6,
            七: 7,
            八: 8,
            九: 9,
            十: 10,
          };
          extractedSeasonNumber =
            chineseNumbers[seasonStr] || parseInt(seasonStr) || undefined;
        }
        break;
      }
    }

    const searchResponse = await fetch(
      `/api/tmdb/search?query=${encodeURIComponent(searchTitle)}`
    );
    if (!searchResponse.ok) {
      throw new Error('搜索失败');
    }
    const searchData = await searchResponse.json();

    if (searchData.results && searchData.results.length > 0) {
      const result = searchData.results[0];
      const detailId = result.id;
      const mediaType = result.media_type || type;

      // 获取详情
      const detailResponse = await fetch(
        `/api/tmdb/detail?id=${detailId}&type=${mediaType}`
      );
      if (!detailResponse.ok) {
        throw new Error('获取TMDB详情失败');
      }
      const detailResult = await detailResponse.json();

      // 如果有季度信息,尝试获取季度详情
      let seasonData = null;
      if (extractedSeasonNumber && mediaType === 'tv') {
        try {
          const seasonResponse = await fetch(
            `/api/tmdb/episodes?id=${detailId}&season=${extractedSeasonNumber}`
          );
          if (seasonResponse.ok) {
            seasonData = await seasonResponse.json();
          }
        } catch (err) {
          console.error('获取季度信息失败', err);
        }
      }

      setDetailData({
        title:
          mediaType === 'movie'
            ? detailResult.title
            : seasonData?.name
            ? `${detailResult.name} ${seasonData.name}`
            : detailResult.name,
        originalTitle:
          mediaType === 'movie'
            ? detailResult.original_title
            : detailResult.original_name,
        year:
          mediaType === 'movie'
            ? detailResult.release_date?.substring(0, 4)
            : seasonData?.air_date?.substring(0, 4) ||
              detailResult.first_air_date?.substring(0, 4),
        poster:
          seasonData?.poster_path || detailResult.poster_path
            ? processImageUrl(
                getTMDBImageUrl(
                  seasonData?.poster_path || detailResult.poster_path,
                  'w500'
                )
              )
            : poster,
        rating: detailResult.vote_average
          ? {
              value: detailResult.vote_average,
              count: detailResult.vote_count,
            }
          : undefined,
        intro: seasonData?.overview || detailResult.overview,
        genres: detailResult.genres?.map((g: any) => g.name),
        countries: detailResult.production_countries?.map((c: any) => c.name),
        languages: detailResult.spoken_languages?.map((l: any) => l.name),
        duration: detailResult.runtime
          ? `${detailResult.runtime}分钟`
          : undefined,
        episodesCount:
          seasonData?.episodes?.length || detailResult.number_of_episodes,
        releaseDate:
          mediaType === 'movie'
            ? detailResult.release_date
            : seasonData?.air_date || detailResult.first_air_date,
        status: detailResult.status,
        tagline: detailResult.tagline,
        seasons: detailResult.number_of_seasons,
        overview: detailResult.overview,
        tmdbId: detailId,
        mediaType: mediaType,
        seasonNumber: extractedSeasonNumber,
        seriesTitle: mediaType === 'tv' ? detailResult.name : undefined,
      });
      setCurrentSource('tmdb');
      return;
    }

    throw new Error('未找到相关内容');
  };

  // 异步获取季度和集数详情（仅TMDB）
  useEffect(() => {
    if (
      !detailData?.tmdbId ||
      !detailData?.mediaType ||
      detailData.mediaType !== 'tv' ||
      seasonsLoaded
    ) {
      return;
    }

    const fetchSeasonData = async () => {
      setLoadingSeasons(true);
      try {
        // 获取所有季度
        const seasonsResponse = await fetch(
          `/api/tmdb/seasons?tvId=${detailData.tmdbId}`
        );
        if (!seasonsResponse.ok) return;
        const seasonsData = await seasonsResponse.json();

        // 设置默认选中季度
        const defaultSeason = detailData.seasonNumber || 1;
        setSelectedSeason(defaultSeason);

        // 获取默认季度的集数详情
        const episodesResponse = await fetch(
          `/api/tmdb/episodes?id=${detailData.tmdbId}&season=${defaultSeason}`
        );
        if (!episodesResponse.ok) return;
        const episodesData = await episodesResponse.json();

        setSeasonData({
          seasons: seasonsData.seasons || [],
          episodes: episodesData.episodes || [],
        });
        setSeasonsLoaded(true);
      } catch (err) {
        console.error('获取季度和集数详情失败:', err);
      } finally {
        setLoadingSeasons(false);
      }
    };

    fetchSeasonData();
  }, [
    detailData?.tmdbId,
    detailData?.mediaType,
    detailData?.seasonNumber,
    seasonsLoaded,
  ]);

  // 自动滚动到当前集数
  useEffect(() => {
    if (
      !currentEpisode ||
      !seasonData?.episodes ||
      !episodesScrollRef.current ||
      currentSource !== 'tmdb'
    ) {
      return;
    }

    // 等待 DOM 更新后再滚动
    const timer = setTimeout(() => {
      const episodeElement = document.getElementById(
        `episode-${currentEpisode}`
      );
      if (episodeElement && episodesScrollRef.current) {
        // 计算滚动位置，使当前集数居中显示
        const container = episodesScrollRef.current;
        const elementLeft = episodeElement.offsetLeft;
        const elementWidth = episodeElement.offsetWidth;
        const containerWidth = container.offsetWidth;
        const scrollLeft = elementLeft - containerWidth / 2 + elementWidth / 2;

        container.scrollLeft = scrollLeft;
      }
    }, 100);

    return () => clearTimeout(timer);
  }, [currentEpisode, seasonData?.episodes, currentSource]);

  // 异步获取演职人员信息（仅TMDB）
  useEffect(() => {
    if (
      !detailData?.tmdbId ||
      !detailData?.mediaType ||
      currentSource !== 'tmdb'
    ) {
      return;
    }

    // 如果已经有演员信息，不重复获取
    if (detailData.actors && detailData.actors.length > 0) {
      return;
    }

    const fetchCredits = async () => {
      try {
        const creditsResponse = await fetch(
          `/api/tmdb/credits?id=${detailData.tmdbId}&type=${detailData.mediaType}`
        );
        if (!creditsResponse.ok) return;
        const creditsData = await creditsResponse.json();

        // 更新演员和导演信息
        setDetailData((prev) =>
          prev
            ? {
                ...prev,
                directors:
                  creditsData.crew
                    ?.filter((person: any) => person.job === 'Director')
                    .slice(0, 5)
                    .map((person: any) => ({
                      name: person.name,
                      profile_path: person.profile_path,
                    })) || prev.directors,
                actors:
                  creditsData.cast?.slice(0, 15).map((person: any) => ({
                    name: person.name,
                    character: person.character,
                    profile_path: person.profile_path,
                  })) || prev.actors,
              }
            : null
        );
      } catch (err) {
        console.error('获取演职人员信息失败:', err);
      }
    };

    fetchCredits();
  }, [
    detailData?.tmdbId,
    detailData?.mediaType,
    currentSource,
    detailData?.actors,
  ]);

  // 切换季度时获取集数
  const handleSeasonChange = async (seasonNumber: number) => {
    if (!detailData?.tmdbId || selectedSeason === seasonNumber) return;

    setSelectedSeason(seasonNumber);
    setLoadingSeasons(true);
    try {
      const episodesResponse = await fetch(
        `/api/tmdb/episodes?id=${detailData.tmdbId}&season=${seasonNumber}`
      );
      if (!episodesResponse.ok) return;
      const episodesData = await episodesResponse.json();

      // 从当前 seasonData 中查找季度信息
      const season = seasonData?.seasons.find(
        (s: any) => s.season_number === seasonNumber
      );

      setSeasonData((prev) => ({
        seasons: prev?.seasons || [],
        episodes: episodesData.episodes || [],
      }));

      // 更新季度元信息
      setDetailData((prev) =>
        prev
          ? {
              ...prev,
              title:
                episodesData.name || season?.name
                  ? `${prev.seriesTitle || prev.title} ${
                      episodesData.name || season?.name
                    }`
                  : prev.title,
              intro: episodesData.overview || season?.overview || prev.overview,
              poster: season?.poster_path
                ? getTMDBImageUrl(season.poster_path, 'w500')
                : prev.poster,
              releaseDate:
                episodesData.air_date || season?.air_date || prev.releaseDate,
              year:
                episodesData.air_date?.substring(0, 4) ||
                season?.air_date?.substring(0, 4) ||
                prev.year,
              episodesCount:
                episodesData.episodes?.length ||
                season?.episode_count ||
                prev.episodesCount,
            }
          : null
      );

      setExpandedEpisodes(new Set());
    } catch (err) {
      console.error('获取集数详情失败:', err);
    } finally {
      setLoadingSeasons(false);
    }
  };

  // 拖动滚动处理函数
  const handleMouseDown = (e: React.MouseEvent) => {
    if (!episodesScrollRef.current) return;
    setIsMouseDown(true);
    setStartX(e.pageX - episodesScrollRef.current.offsetLeft);
    setScrollLeft(episodesScrollRef.current.scrollLeft);
  };

  const handleMouseMove = (e: React.MouseEvent) => {
    if (!isMouseDown || !episodesScrollRef.current) return;

    const x = e.pageX - episodesScrollRef.current.offsetLeft;
    const distance = Math.abs(x - startX);

    // 只有移动超过5px才进入拖动模式
    if (distance > 5 && !isDragging) {
      setIsDragging(true);
      episodesScrollRef.current.style.cursor = 'grabbing';
      episodesScrollRef.current.style.userSelect = 'none';
    }

    if (isDragging) {
      e.preventDefault();
      const walk = (x - startX) * 2; // 滚动速度倍数
      episodesScrollRef.current.scrollLeft = scrollLeft - walk;
    }
  };

  const handleMouseUp = () => {
    setIsMouseDown(false);
    setIsDragging(false);
    if (episodesScrollRef.current) {
      episodesScrollRef.current.style.cursor = 'grab';
      episodesScrollRef.current.style.userSelect = 'auto';
    }
  };

  const handleMouseLeave = () => {
    if (isMouseDown || isDragging) {
      setIsMouseDown(false);
      setIsDragging(false);
      if (episodesScrollRef.current) {
        episodesScrollRef.current.style.cursor = 'grab';
        episodesScrollRef.current.style.userSelect = 'auto';
      }
    }
  };

  // 演员列表拖动滚动处理函数
  const handleActorsMouseDown = (e: React.MouseEvent) => {
    if (!actorsScrollRef.current) return;
    setIsActorsMouseDown(true);
    setActorsStartX(e.pageX - actorsScrollRef.current.offsetLeft);
    setActorsScrollLeft(actorsScrollRef.current.scrollLeft);
  };

  const handleActorsMouseMove = (e: React.MouseEvent) => {
    if (!isActorsMouseDown || !actorsScrollRef.current) return;

    const x = e.pageX - actorsScrollRef.current.offsetLeft;
    const distance = Math.abs(x - actorsStartX);

    // 只有移动超过5px才进入拖动模式
    if (distance > 5 && !isActorsDragging) {
      setIsActorsDragging(true);
      actorsScrollRef.current.style.cursor = 'grabbing';
      actorsScrollRef.current.style.userSelect = 'none';
    }

    if (isActorsDragging) {
      e.preventDefault();
      const walk = (x - actorsStartX) * 2; // 滚动速度倍数
      actorsScrollRef.current.scrollLeft = actorsScrollLeft - walk;
    }
  };

  const handleActorsMouseUp = () => {
    setIsActorsMouseDown(false);
    setIsActorsDragging(false);
    if (actorsScrollRef.current) {
      actorsScrollRef.current.style.cursor = 'grab';
      actorsScrollRef.current.style.userSelect = 'auto';
    }
  };

  const handleActorsMouseLeave = () => {
    if (isActorsMouseDown || isActorsDragging) {
      setIsActorsMouseDown(false);
      setIsActorsDragging(false);
      if (actorsScrollRef.current) {
        actorsScrollRef.current.style.cursor = 'grab';
        actorsScrollRef.current.style.userSelect = 'auto';
      }
    }
  };

  const galleryEntryButton = canShowGalleryEntry ? (
    <button
      onClick={openGallery}
      className='inline-flex items-center gap-2 px-3 py-1.5 text-sm rounded-lg bg-blue-500 hover:bg-blue-600 text-white transition-colors'
    >
      <Images size={16} />
      照片墙
    </button>
  ) : null;

  const virtualGalleryLayout = React.useMemo(() => {
    if (galleryImages.length === 0 || galleryViewportWidth <= 0) {
      return {
        visibleItems: [] as Array<
          GalleryImage & {
            top: number;
            left: number;
            renderWidth: number;
            renderHeight: number;
            index: number;
          }
        >,
        totalHeight: 0,
        usedWidth: 0,
      };
    }

    const gap = 4;
    const overscan = 800;
    const horizontalPadding = 32;
    const width = Math.max(galleryViewportWidth - horizontalPadding, 0);
    const columnCount =
      width >= 1280 ? 5 : width >= 1024 ? 4 : width >= 640 ? 3 : 2;
    const columnWidth = Math.floor(
      (width - gap * (columnCount - 1)) / columnCount
    );
    const usedWidth = columnWidth * columnCount + gap * (columnCount - 1);
    const columnHeights = new Array(columnCount).fill(0);

    const items = galleryImages.map((image, index) => {
      let targetColumn = 0;
      for (let i = 1; i < columnCount; i++) {
        if (columnHeights[i] < columnHeights[targetColumn]) {
          targetColumn = i;
        }
      }

      const ratio =
        image.width && image.height
          ? image.height / image.width
          : image.imageType === 'poster'
          ? 1.5
          : 0.5625;
      const renderHeight = Math.max(Math.round(columnWidth * ratio), 80);
      const top = columnHeights[targetColumn];
      const left = targetColumn * (columnWidth + gap);

      columnHeights[targetColumn] += renderHeight + gap;

      return {
        ...image,
        index,
        top,
        left,
        renderWidth: columnWidth,
        renderHeight,
      };
    });

    const totalHeight = Math.max(...columnHeights, 0);
    const minVisibleTop = Math.max(galleryScrollTop - overscan, 0);
    const maxVisibleBottom =
      galleryScrollTop + galleryViewportHeight + overscan;
    const visibleItems = items.filter(
      (item) =>
        item.top + item.renderHeight >= minVisibleTop &&
        item.top <= maxVisibleBottom
    );

    return { visibleItems, totalHeight, usedWidth };
  }, [
    galleryImages,
    galleryScrollTop,
    galleryViewportHeight,
    galleryViewportWidth,
  ]);

  const galleryBody = (
    <div
      ref={galleryScrollRef}
      className='flex-1 overflow-y-auto overflow-x-hidden p-4'
    >
      {galleryLoading && (
        <div className='flex items-center justify-center py-20'>
          <div className='animate-spin rounded-full h-10 w-10 border-b-2 border-green-500'></div>
        </div>
      )}

      {!galleryLoading && galleryError && (
        <div className='text-center py-12 text-red-500 dark:text-red-400'>
          {galleryError}
        </div>
      )}

      {!galleryLoading && !galleryError && galleryImages.length === 0 && (
        <div className='text-center py-12 text-gray-500 dark:text-gray-400'>
          暂无图片
        </div>
      )}

      {!galleryLoading && !galleryError && galleryImages.length > 0 && (
        <div
          className='relative mx-auto'
          style={{
            height: virtualGalleryLayout.totalHeight,
            width: virtualGalleryLayout.usedWidth || '100%',
          }}
        >
          {virtualGalleryLayout.visibleItems.map((image) => {
            const imageUrl = getTMDBImageUrl(
              image.file_path,
              image.imageType === 'poster' ? 'w500' : 'original'
            );
            const thumbUrl = getTMDBImageUrl(
              image.file_path,
              image.imageType === 'poster' ? 'w342' : 'w780'
            );

            return (
              <div
                key={`${image.imageType}-${image.file_path}-${image.index}`}
                className='group absolute'
                style={{
                  top: image.top,
                  left: image.left,
                  width: image.renderWidth,
                  height: image.renderHeight,
                }}
              >
                <div
                  className='relative w-full h-full overflow-hidden rounded-md bg-gray-100 dark:bg-gray-800 cursor-pointer hover:opacity-90 transition-opacity'
                  onClick={() => handleImageClick(imageUrl)}
                >
                  <ProxyImage
                    originalSrc={thumbUrl}
                    alt={`${detailData?.title || title}-gallery-${
                      image.index + 1
                    }`}
                    className='absolute inset-0 w-full h-full object-cover'
                    draggable={false}
                  />
                  <div className='absolute left-2 top-2 px-2 py-0.5 rounded-full text-xs bg-black/60 text-white'>
                    {image.imageType === 'poster' ? '海报' : '剧照'}
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );

  const galleryHeader = (
    <div className='flex items-center justify-between p-4 border-b border-gray-100 dark:border-gray-800'>
      <div>
        <h3 className='text-lg font-semibold text-gray-900 dark:text-gray-100'>
          照片墙
        </h3>
        {!galleryLoading && (
          <p className='text-sm text-gray-500 dark:text-gray-400'>
            共 {galleryTotal} 张
          </p>
        )}
      </div>
      <button
        onClick={() => setShowGallery(false)}
        className='p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors'
        aria-label='关闭照片墙'
      >
        <X size={20} className='text-gray-500 dark:text-gray-400' />
      </button>
    </div>
  );

  const galleryModal = showGallery ? (
    useDrawer ? (
      <div className='fixed inset-0 z-[10000] flex items-center justify-end pointer-events-none'>
        <div
          className={`relative ${drawerWidth} h-full bg-white dark:bg-gray-900 shadow-2xl overflow-hidden flex flex-col pointer-events-auto`}
        >
          {galleryHeader}
          {galleryBody}
        </div>
      </div>
    ) : (
      <div className='fixed inset-0 z-[10000] flex items-center justify-center p-4'>
        <div
          className='absolute inset-0 bg-black/60'
          onClick={() => setShowGallery(false)}
        />
        <div className='relative w-full max-w-6xl max-h-[90vh] bg-white dark:bg-gray-900 rounded-2xl shadow-2xl overflow-hidden flex flex-col'>
          {galleryHeader}
          {galleryBody}
        </div>
      </div>
    )
  ) : null;

  if (!isVisible || !mounted) return null;

  const content = useDrawer ? (
    <div className='fixed inset-0 z-[9999] flex items-center justify-end pointer-events-none'>
      {/* 详情面板 - 抽屉模式 */}
      <div
        className={`relative ${drawerWidth} h-full bg-white dark:bg-gray-900 shadow-2xl overflow-hidden flex flex-col transition-transform duration-300 ease-out pointer-events-auto ${
          isAnimating ? 'translate-x-0' : 'translate-x-full'
        }`}
      >
        {/* 头部 */}
        <div className='flex items-center justify-between p-4 border-b border-gray-100 dark:border-gray-800 sticky top-0 bg-white dark:bg-gray-900 z-10'>
          <h2 className='text-xl font-semibold text-gray-900 dark:text-gray-100'>
            详情
          </h2>
          <div className='flex items-center gap-2'>
            {externalUrl && (
              <button
                onClick={() =>
                  window.open(externalUrl, '_blank', 'noopener,noreferrer')
                }
                className='p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors duration-150'
                title='打开外部页面'
                aria-label='打开外部页面'
              >
                <ExternalLink
                  size={18}
                  className='text-gray-500 dark:text-gray-400'
                />
              </button>
            )}
            <button
              onClick={onClose}
              className='p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors duration-150'
              title='关闭'
              aria-label='关闭'
            >
              <X size={20} className='text-gray-500 dark:text-gray-400' />
            </button>
          </div>
        </div>

        {/* 内容区域 */}
        <div className='overflow-y-auto max-h-[calc(90vh-4rem)]'>
          {loading && (
            <div className='flex items-center justify-center py-20'>
              <div className='animate-spin rounded-full h-12 w-12 border-b-2 border-green-500'></div>
            </div>
          )}

          {error && (
            <div className='p-6'>
              <div className='text-center mb-6'>
                <p className='text-red-500 dark:text-red-400'>{error}</p>
              </div>

              {/* 数据源显示和切换 - 错误时也显示 */}
              <div className='mt-6 pt-4 border-t border-gray-200 dark:border-gray-700'>
                <div className='flex items-center justify-between gap-3 flex-wrap'>
                  <div className='flex items-center gap-2'>
                    <span className='text-sm text-gray-500 dark:text-gray-400'>
                      数据来源:
                    </span>
                    <span className='text-sm font-medium text-gray-700 dark:text-gray-300 uppercase'>
                      {currentSource === 'douban' && 'Douban'}
                      {currentSource === 'bangumi' && 'Bangumi'}
                      {currentSource === 'cms' && 'CMS'}
                      {currentSource === 'tmdb' && 'TMDB'}
                    </span>
                  </div>
                  <div className='flex items-center gap-2 flex-wrap'>
                    {galleryEntryButton}
                    {currentSource !== 'tmdb' && (
                      <button
                        onClick={handleToggleSource}
                        disabled={loading}
                        className='px-3 py-1.5 text-sm rounded-lg bg-green-500 hover:bg-green-600 text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed'
                      >
                        切换到 TMDB
                      </button>
                    )}
                    {currentSource === 'tmdb' &&
                      originalSource !== 'tmdb' &&
                      originalDetailData && (
                        <button
                          onClick={handleToggleSource}
                          disabled={loading}
                          className='px-3 py-1.5 text-sm rounded-lg bg-gray-500 hover:bg-gray-600 text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed'
                        >
                          切换回{' '}
                          {originalSource === 'douban'
                            ? 'Douban'
                            : originalSource === 'bangumi'
                            ? 'Bangumi'
                            : 'CMS'}
                        </button>
                      )}
                  </div>
                </div>
              </div>
            </div>
          )}

          {!loading && !error && detailData && (
            <div className='p-6'>
              {/* 海报和基本信息 */}
              <div className='flex gap-6 mb-6'>
                {detailData.poster && (
                  <div className='flex flex-col items-start gap-3 flex-shrink-0'>
                    <div
                      className='relative w-32 h-48 rounded-lg overflow-hidden bg-gray-100 dark:bg-gray-800 cursor-pointer hover:opacity-90 transition-opacity'
                      onClick={() => handleImageClick(detailData.poster!)}
                    >
                      <ProxyImage
                        originalSrc={detailData.poster}
                        alt={detailData.title}
                        className='absolute inset-0 w-full h-full object-cover'
                        draggable={false}
                      />
                    </div>
                    {galleryEntryButton}
                  </div>
                )}
                <div className='flex-1 min-w-0'>
                  <h3 className='text-2xl font-bold text-gray-900 dark:text-gray-100 mb-2'>
                    {detailData.title}
                  </h3>
                  {detailData.originalTitle &&
                    detailData.originalTitle !== detailData.title && (
                      <p className='text-sm text-gray-500 dark:text-gray-400 mb-3'>
                        {detailData.originalTitle}
                      </p>
                    )}

                  {/* 评分 */}
                  {detailData.rating && (
                    <div className='flex items-center gap-2 mb-3'>
                      <Star
                        size={20}
                        className='text-yellow-500 fill-yellow-500'
                      />
                      <span className='text-lg font-semibold text-gray-900 dark:text-gray-100'>
                        {detailData.rating.value.toFixed(1)}
                      </span>
                      {detailData.rating.count > 0 && (
                        <span className='text-sm text-gray-500 dark:text-gray-400'>
                          ({detailData.rating.count} 评价)
                        </span>
                      )}
                    </div>
                  )}

                  {/* 类型标签 */}
                  {detailData.genres && detailData.genres.length > 0 && (
                    <div className='flex flex-wrap gap-2 mb-3'>
                      {detailData.genres.map((genre, index) => (
                        <span
                          key={index}
                          className='px-2 py-1 text-xs rounded bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300'
                        >
                          {genre}
                        </span>
                      ))}
                    </div>
                  )}

                  {/* 年份和时长 */}
                  <div className='flex flex-wrap gap-4 text-sm text-gray-600 dark:text-gray-400'>
                    {detailData.year && (
                      <div className='flex items-center gap-1'>
                        <Calendar size={16} />
                        <span>{detailData.year}</span>
                      </div>
                    )}
                    {detailData.duration && (
                      <div className='flex items-center gap-1'>
                        <Clock size={16} />
                        <span>{detailData.duration}</span>
                      </div>
                    )}
                    {detailData.episodesCount && (
                      <div className='flex items-center gap-1'>
                        <Film size={16} />
                        <span>{detailData.episodesCount} 集</span>
                      </div>
                    )}
                  </div>
                </div>
              </div>

              {/* 简介 */}
              {(detailData.intro || detailData.overview) && (
                <div className='mb-6'>
                  <h4 className='text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2'>
                    简介
                  </h4>
                  <p className='text-gray-700 dark:text-gray-300 leading-relaxed whitespace-pre-wrap'>
                    {detailData.intro || detailData.overview}
                  </p>
                </div>
              )}

              {/* 导演和演员 */}
              {detailData.directors && detailData.directors.length > 0 && (
                <div className='mb-4'>
                  <h4 className='text-sm font-semibold text-gray-900 dark:text-gray-100 mb-2 flex items-center gap-2'>
                    <Users size={16} />
                    导演
                  </h4>
                  <p className='text-gray-700 dark:text-gray-300'>
                    {detailData.directors.map((d) => d.name).join(', ')}
                  </p>
                </div>
              )}

              {detailData.actors && detailData.actors.length > 0 && (
                <div className='mb-4'>
                  <h4 className='text-sm font-semibold text-gray-900 dark:text-gray-100 mb-2 flex items-center gap-2'>
                    <Users size={16} />
                    演员
                  </h4>
                  {currentSource === 'tmdb' ? (
                    <div
                      ref={actorsScrollRef}
                      onMouseDown={handleActorsMouseDown}
                      onMouseMove={handleActorsMouseMove}
                      onMouseUp={handleActorsMouseUp}
                      onMouseLeave={handleActorsMouseLeave}
                      className='overflow-x-auto -mx-6 px-6 cursor-grab active:cursor-grabbing'
                      style={{
                        scrollbarWidth: 'thin',
                        scrollBehavior: isActorsDragging ? 'auto' : 'smooth',
                      }}
                    >
                      <div className='flex gap-4 pb-2'>
                        {detailData.actors.map((actor, index) => (
                          <div
                            key={index}
                            className='flex flex-col items-center flex-shrink-0'
                            style={{
                              pointerEvents: isActorsDragging ? 'none' : 'auto',
                            }}
                          >
                            {actor.profile_path ? (
                              <div
                                className='relative w-20 h-20 rounded-full overflow-hidden bg-gray-200 dark:bg-gray-700 mb-2 cursor-pointer hover:opacity-80 transition-opacity'
                                onClick={() =>
                                  handleImageClick(
                                    getTMDBImageUrl(
                                      actor.profile_path || null,
                                      'w185'
                                    )
                                  )
                                }
                              >
                                <ProxyImage
                                  originalSrc={getTMDBImageUrl(
                                    actor.profile_path || null,
                                    'w185'
                                  )}
                                  alt={actor.name}
                                  className='absolute inset-0 w-full h-full object-cover'
                                  draggable={false}
                                />
                              </div>
                            ) : (
                              <div className='w-20 h-20 rounded-full bg-gray-200 dark:bg-gray-700 mb-2 flex items-center justify-center'>
                                <Users size={28} className='text-gray-400' />
                              </div>
                            )}
                            <a
                              href={`https://baike.baidu.com/item/${encodeURIComponent(
                                actor.name
                              )}`}
                              target='_blank'
                              rel='noopener noreferrer'
                              className='text-xs font-medium text-gray-900 dark:text-gray-100 text-center w-20 line-clamp-2 hover:text-green-600 dark:hover:text-green-400 transition-colors cursor-pointer'
                              onClick={(e) => e.stopPropagation()}
                            >
                              {actor.name}
                            </a>
                            {actor.character && (
                              <p className='text-xs text-gray-500 dark:text-gray-400 text-center w-20 line-clamp-2'>
                                {actor.character}
                              </p>
                            )}
                          </div>
                        ))}
                      </div>
                    </div>
                  ) : (
                    <p className='text-gray-700 dark:text-gray-300'>
                      {detailData.actors
                        .slice(0, 10)
                        .map((a) => a.name)
                        .join(', ')}
                    </p>
                  )}
                </div>
              )}

              {/* 制作信息 */}
              <div className='grid grid-cols-2 gap-4 text-sm'>
                {detailData.countries && detailData.countries.length > 0 && (
                  <div>
                    <h4 className='font-semibold text-gray-900 dark:text-gray-100 mb-1 flex items-center gap-1'>
                      <Globe size={14} />
                      国家/地区
                    </h4>
                    <p className='text-gray-700 dark:text-gray-300'>
                      {detailData.countries.join(', ')}
                    </p>
                  </div>
                )}

                {detailData.languages && detailData.languages.length > 0 && (
                  <div>
                    <h4 className='font-semibold text-gray-900 dark:text-gray-100 mb-1 flex items-center gap-1'>
                      <Tag size={14} />
                      语言
                    </h4>
                    <p className='text-gray-700 dark:text-gray-300'>
                      {detailData.languages.join(', ')}
                    </p>
                  </div>
                )}

                {detailData.releaseDate && (
                  <div>
                    <h4 className='font-semibold text-gray-900 dark:text-gray-100 mb-1 flex items-center gap-1'>
                      <Calendar size={14} />
                      上映日期
                    </h4>
                    <p className='text-gray-700 dark:text-gray-300'>
                      {detailData.releaseDate}
                    </p>
                  </div>
                )}

                {detailData.status && (
                  <div>
                    <h4 className='font-semibold text-gray-900 dark:text-gray-100 mb-1'>
                      状态
                    </h4>
                    <p className='text-gray-700 dark:text-gray-300'>
                      {detailData.status}
                    </p>
                  </div>
                )}
              </div>

              {/* 季度和集数信息（仅TMDB电视剧） */}
              {detailData.mediaType === 'tv' && (
                <div className='mt-6'>
                  {loadingSeasons && (
                    <div className='flex items-center justify-center py-4'>
                      <div className='animate-spin rounded-full h-8 w-8 border-b-2 border-green-500'></div>
                    </div>
                  )}

                  {!loadingSeasons && seasonData && (
                    <>
                      {/* 季度列表 */}
                      {seasonData.seasons.length > 0 && (
                        <div className='mb-6'>
                          <h4 className='text-lg font-semibold text-gray-900 dark:text-gray-100 mb-3'>
                            季度
                          </h4>
                          <div className='grid grid-cols-2 sm:grid-cols-3 gap-3'>
                            {seasonData.seasons.map((season: any) => (
                              <div
                                key={season.id}
                                onClick={() =>
                                  handleSeasonChange(season.season_number)
                                }
                                className={`flex items-center gap-2 p-2 rounded cursor-pointer transition-colors ${
                                  selectedSeason === season.season_number
                                    ? 'bg-green-100 dark:bg-green-900/30 ring-2 ring-green-500'
                                    : 'bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700'
                                }`}
                              >
                                {season.poster_path && (
                                  <div
                                    className='relative w-12 h-16 rounded overflow-hidden bg-gray-200 dark:bg-gray-700 flex-shrink-0 hover:opacity-80 transition-opacity'
                                    onClick={(e) => {
                                      e.stopPropagation();
                                      handleImageClick(
                                        getTMDBImageUrl(
                                          season.poster_path,
                                          'w500'
                                        )
                                      );
                                    }}
                                  >
                                    <ProxyImage
                                      originalSrc={getTMDBImageUrl(
                                        season.poster_path,
                                        'w92'
                                      )}
                                      alt={season.name}
                                      className='absolute inset-0 w-full h-full object-cover'
                                      draggable={false}
                                    />
                                  </div>
                                )}
                                <div className='flex-1 min-w-0'>
                                  <p className='text-sm font-medium text-gray-900 dark:text-gray-100 truncate'>
                                    {season.name}
                                  </p>
                                  <p className='text-xs text-gray-500 dark:text-gray-400'>
                                    {season.episode_count} 集
                                  </p>
                                </div>
                              </div>
                            ))}
                          </div>
                        </div>
                      )}

                      {/* 集数列表 */}
                      {seasonData.episodes.length > 0 && (
                        <div>
                          <h4 className='text-lg font-semibold text-gray-900 dark:text-gray-100 mb-3'>
                            {seasonData.seasons.find(
                              (s: any) => s.season_number === selectedSeason
                            )?.name || `第${selectedSeason}季`}
                          </h4>
                          <div
                            ref={episodesScrollRef}
                            onMouseDown={handleMouseDown}
                            onMouseMove={handleMouseMove}
                            onMouseUp={handleMouseUp}
                            onMouseLeave={handleMouseLeave}
                            className='overflow-x-auto -mx-6 px-6 cursor-grab active:cursor-grabbing'
                            style={{
                              scrollbarWidth: 'thin',
                              scrollBehavior: isDragging ? 'auto' : 'smooth',
                            }}
                          >
                            <div className='flex gap-3 py-2'>
                              {seasonData.episodes.map((episode: Episode) => {
                                const isExpanded = expandedEpisodes.has(
                                  episode.id
                                );
                                const isCurrentEpisode =
                                  currentEpisode === episode.episode_number;
                                return (
                                  <div
                                    key={episode.id}
                                    id={`episode-${episode.episode_number}`}
                                    className={`flex-shrink-0 w-64 p-3 rounded ${
                                      isCurrentEpisode
                                        ? 'bg-green-100 dark:bg-green-900/30 ring-2 ring-green-500'
                                        : 'bg-gray-50 dark:bg-gray-800'
                                    }`}
                                    style={{
                                      pointerEvents: isDragging
                                        ? 'none'
                                        : 'auto',
                                    }}
                                  >
                                    {episode.still_path && (
                                      <div
                                        className='relative w-full h-36 rounded overflow-hidden bg-gray-200 dark:bg-gray-700 mb-2 cursor-pointer hover:opacity-90 transition-opacity'
                                        onClick={() =>
                                          handleImageClick(
                                            getTMDBImageUrl(
                                              episode.still_path,
                                              'w500'
                                            )
                                          )
                                        }
                                      >
                                        <ProxyImage
                                          originalSrc={getTMDBImageUrl(
                                            episode.still_path,
                                            'w300'
                                          )}
                                          alt={episode.name}
                                          className='absolute inset-0 w-full h-full object-cover'
                                          draggable={false}
                                        />
                                      </div>
                                    )}
                                    <p className='text-sm font-medium text-gray-900 dark:text-gray-100 mb-1'>
                                      第{episode.episode_number}集:{' '}
                                      {episode.name}
                                    </p>
                                    {episode.overview && (
                                      <p
                                        onClick={() => {
                                          const newExpanded = new Set(
                                            expandedEpisodes
                                          );
                                          if (isExpanded) {
                                            newExpanded.delete(episode.id);
                                          } else {
                                            newExpanded.add(episode.id);
                                          }
                                          setExpandedEpisodes(newExpanded);
                                        }}
                                        className={`text-xs text-gray-600 dark:text-gray-400 cursor-pointer ${
                                          isExpanded ? '' : 'line-clamp-3'
                                        }`}
                                      >
                                        {episode.overview}
                                      </p>
                                    )}
                                    {episode.air_date && (
                                      <p className='text-xs text-gray-500 dark:text-gray-500 mt-1'>
                                        {episode.air_date}
                                      </p>
                                    )}
                                  </div>
                                );
                              })}
                            </div>
                          </div>
                        </div>
                      )}
                    </>
                  )}
                </div>
              )}

              {/* 数据源显示和切换 */}
              <div className='mt-6 pt-4 border-t border-gray-200 dark:border-gray-700'>
                <div className='flex items-center justify-between gap-3 flex-wrap'>
                  <div className='flex items-center gap-2'>
                    <span className='text-sm text-gray-500 dark:text-gray-400'>
                      数据来源:
                    </span>
                    <span className='text-sm font-medium text-gray-700 dark:text-gray-300 uppercase'>
                      {currentSource === 'douban' && 'Douban'}
                      {currentSource === 'bangumi' && 'Bangumi'}
                      {currentSource === 'cms' && 'CMS'}
                      {currentSource === 'tmdb' && 'TMDB'}
                    </span>
                  </div>
                  <div className='flex items-center gap-2 flex-wrap'>
                    {galleryEntryButton}
                    {currentSource !== 'tmdb' && (
                      <button
                        onClick={handleToggleSource}
                        disabled={loading}
                        className='px-3 py-1.5 text-sm rounded-lg bg-green-500 hover:bg-green-600 text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed'
                      >
                        切换到 TMDB
                      </button>
                    )}
                    {currentSource === 'tmdb' &&
                      originalSource !== 'tmdb' &&
                      originalDetailData && (
                        <button
                          onClick={handleToggleSource}
                          disabled={loading}
                          className='px-3 py-1.5 text-sm rounded-lg bg-gray-500 hover:bg-gray-600 text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed'
                        >
                          切换回{' '}
                          {originalSource === 'douban'
                            ? 'Douban'
                            : originalSource === 'bangumi'
                            ? 'Bangumi'
                            : 'CMS'}
                        </button>
                      )}
                  </div>
                </div>
              </div>
            </div>
          )}
        </div>
      </div>

      {/* 图片查看器 */}
      {galleryModal}
      {showImageViewer && (
        <ImageViewer
          isOpen={showImageViewer}
          onClose={() => setShowImageViewer(false)}
          imageUrl={selectedImage}
          alt={detailData?.title || title}
        />
      )}
    </div>
  ) : (
    <div className='fixed inset-0 z-[9999] flex items-center justify-center p-4'>
      {/* 背景遮罩 */}
      <div
        className={`absolute inset-0 bg-black/50 transition-opacity duration-200 ease-out ${
          isAnimating ? 'opacity-100' : 'opacity-0'
        }`}
        onClick={onClose}
        style={{
          backdropFilter: 'blur(4px)',
          willChange: 'opacity',
        }}
      />

      {/* 详情面板 - 居中模式 */}
      <div
        className='relative w-full max-w-2xl max-h-[90vh] bg-white dark:bg-gray-900 rounded-2xl shadow-2xl overflow-hidden transition-all duration-200 ease-out'
        style={{
          willChange: 'transform, opacity',
          backfaceVisibility: 'hidden',
          transform: isAnimating
            ? 'scale(1) translateZ(0)'
            : 'scale(0.95) translateZ(0)',
          opacity: isAnimating ? 1 : 0,
        }}
      >
        {/* 头部 */}
        <div className='flex items-center justify-between p-4 border-b border-gray-100 dark:border-gray-800 sticky top-0 bg-white dark:bg-gray-900 z-10'>
          <h2 className='text-xl font-semibold text-gray-900 dark:text-gray-100'>
            详情
          </h2>
          <div className='flex items-center gap-2'>
            {externalUrl && (
              <button
                onClick={() =>
                  window.open(externalUrl, '_blank', 'noopener,noreferrer')
                }
                className='p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors duration-150'
                title='打开外部页面'
                aria-label='打开外部页面'
              >
                <ExternalLink
                  size={18}
                  className='text-gray-500 dark:text-gray-400'
                />
              </button>
            )}
            <button
              onClick={onClose}
              className='p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors duration-150'
              title='关闭'
              aria-label='关闭'
            >
              <X size={20} className='text-gray-500 dark:text-gray-400' />
            </button>
          </div>
        </div>

        {/* 内容区域 */}
        <div className='overflow-y-auto max-h-[calc(90vh-4rem)]'>
          {loading && (
            <div className='flex items-center justify-center py-20'>
              <div className='animate-spin rounded-full h-12 w-12 border-b-2 border-green-500'></div>
            </div>
          )}

          {error && (
            <div className='p-6'>
              <div className='text-center mb-6'>
                <p className='text-red-500 dark:text-red-400'>{error}</p>
              </div>

              {/* 数据源显示和切换 - 错误时也显示 */}
              <div className='mt-6 pt-4 border-t border-gray-200 dark:border-gray-700'>
                <div className='flex items-center justify-between'>
                  <div className='flex items-center gap-2'>
                    <span className='text-sm text-gray-500 dark:text-gray-400'>
                      数据来源:
                    </span>
                    <span className='text-sm font-medium text-gray-700 dark:text-gray-300 uppercase'>
                      {currentSource === 'douban' && 'Douban'}
                      {currentSource === 'bangumi' && 'Bangumi'}
                      {currentSource === 'cms' && 'CMS'}
                      {currentSource === 'tmdb' && 'TMDB'}
                    </span>
                  </div>
                  {currentSource !== 'tmdb' && (
                    <button
                      onClick={handleToggleSource}
                      disabled={loading}
                      className='px-3 py-1.5 text-sm rounded-lg bg-green-500 hover:bg-green-600 text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed'
                    >
                      切换到 TMDB
                    </button>
                  )}
                  {currentSource === 'tmdb' &&
                    originalSource !== 'tmdb' &&
                    originalDetailData && (
                      <button
                        onClick={handleToggleSource}
                        disabled={loading}
                        className='px-3 py-1.5 text-sm rounded-lg bg-gray-500 hover:bg-gray-600 text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed'
                      >
                        切换回{' '}
                        {originalSource === 'douban'
                          ? 'Douban'
                          : originalSource === 'bangumi'
                          ? 'Bangumi'
                          : 'CMS'}
                      </button>
                    )}
                </div>
              </div>
            </div>
          )}

          {!loading && !error && detailData && (
            <div className='p-6'>
              {/* 海报和基本信息 */}
              <div className='flex gap-6 mb-6'>
                {detailData.poster && (
                  <div className='flex flex-col items-start gap-3 flex-shrink-0'>
                    <div
                      className='relative w-32 h-48 rounded-lg overflow-hidden bg-gray-100 dark:bg-gray-800 cursor-pointer hover:opacity-90 transition-opacity'
                      onClick={() => handleImageClick(detailData.poster!)}
                    >
                      <ProxyImage
                        originalSrc={detailData.poster}
                        alt={detailData.title}
                        className='absolute inset-0 w-full h-full object-cover'
                        draggable={false}
                      />
                    </div>
                    {galleryEntryButton}
                  </div>
                )}
                <div className='flex-1 min-w-0'>
                  <h3 className='text-2xl font-bold text-gray-900 dark:text-gray-100 mb-2'>
                    {detailData.title}
                  </h3>
                  {detailData.originalTitle &&
                    detailData.originalTitle !== detailData.title && (
                      <p className='text-sm text-gray-500 dark:text-gray-400 mb-3'>
                        {detailData.originalTitle}
                      </p>
                    )}

                  {/* 评分 */}
                  {detailData.rating && (
                    <div className='flex items-center gap-2 mb-3'>
                      <Star
                        size={20}
                        className='text-yellow-500 fill-yellow-500'
                      />
                      <span className='text-lg font-semibold text-gray-900 dark:text-gray-100'>
                        {detailData.rating.value.toFixed(1)}
                      </span>
                      {detailData.rating.count > 0 && (
                        <span className='text-sm text-gray-500 dark:text-gray-400'>
                          ({detailData.rating.count} 评价)
                        </span>
                      )}
                    </div>
                  )}

                  {/* 类型标签 */}
                  {detailData.genres && detailData.genres.length > 0 && (
                    <div className='flex flex-wrap gap-2 mb-3'>
                      {detailData.genres.map((genre, index) => (
                        <span
                          key={index}
                          className='px-2 py-1 text-xs rounded bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300'
                        >
                          {genre}
                        </span>
                      ))}
                    </div>
                  )}

                  {/* 年份和时长 */}
                  <div className='flex flex-wrap gap-4 text-sm text-gray-600 dark:text-gray-400'>
                    {detailData.year && (
                      <div className='flex items-center gap-1'>
                        <Calendar size={16} />
                        <span>{detailData.year}</span>
                      </div>
                    )}
                    {detailData.duration && (
                      <div className='flex items-center gap-1'>
                        <Clock size={16} />
                        <span>{detailData.duration}</span>
                      </div>
                    )}
                    {detailData.episodesCount && (
                      <div className='flex items-center gap-1'>
                        <Film size={16} />
                        <span>{detailData.episodesCount} 集</span>
                      </div>
                    )}
                  </div>
                </div>
              </div>

              {/* 简介 */}
              {(detailData.intro || detailData.overview) && (
                <div className='mb-6'>
                  <h4 className='text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2'>
                    简介
                  </h4>
                  <p className='text-gray-700 dark:text-gray-300 leading-relaxed whitespace-pre-wrap'>
                    {detailData.intro || detailData.overview}
                  </p>
                </div>
              )}

              {/* 导演和演员 */}
              {detailData.directors && detailData.directors.length > 0 && (
                <div className='mb-4'>
                  <h4 className='text-sm font-semibold text-gray-900 dark:text-gray-100 mb-2 flex items-center gap-2'>
                    <Users size={16} />
                    导演
                  </h4>
                  <p className='text-gray-700 dark:text-gray-300'>
                    {detailData.directors.map((d) => d.name).join(', ')}
                  </p>
                </div>
              )}

              {detailData.actors && detailData.actors.length > 0 && (
                <div className='mb-4'>
                  <h4 className='text-sm font-semibold text-gray-900 dark:text-gray-100 mb-2 flex items-center gap-2'>
                    <Users size={16} />
                    演员
                  </h4>
                  {currentSource === 'tmdb' ? (
                    <div
                      ref={actorsScrollRef}
                      onMouseDown={handleActorsMouseDown}
                      onMouseMove={handleActorsMouseMove}
                      onMouseUp={handleActorsMouseUp}
                      onMouseLeave={handleActorsMouseLeave}
                      className='overflow-x-auto -mx-6 px-6 cursor-grab active:cursor-grabbing'
                      style={{
                        scrollbarWidth: 'thin',
                        scrollBehavior: isActorsDragging ? 'auto' : 'smooth',
                      }}
                    >
                      <div className='flex gap-4 pb-2'>
                        {detailData.actors.map((actor, index) => (
                          <div
                            key={index}
                            className='flex flex-col items-center flex-shrink-0'
                            style={{
                              pointerEvents: isActorsDragging ? 'none' : 'auto',
                            }}
                          >
                            {actor.profile_path ? (
                              <div
                                className='relative w-20 h-20 rounded-full overflow-hidden bg-gray-200 dark:bg-gray-700 mb-2 cursor-pointer hover:opacity-80 transition-opacity'
                                onClick={() =>
                                  handleImageClick(
                                    getTMDBImageUrl(
                                      actor.profile_path || null,
                                      'w185'
                                    )
                                  )
                                }
                              >
                                <ProxyImage
                                  originalSrc={getTMDBImageUrl(
                                    actor.profile_path || null,
                                    'w185'
                                  )}
                                  alt={actor.name}
                                  className='absolute inset-0 w-full h-full object-cover'
                                  draggable={false}
                                />
                              </div>
                            ) : (
                              <div className='w-20 h-20 rounded-full bg-gray-200 dark:bg-gray-700 mb-2 flex items-center justify-center'>
                                <Users size={28} className='text-gray-400' />
                              </div>
                            )}
                            <a
                              href={`https://baike.baidu.com/item/${encodeURIComponent(
                                actor.name
                              )}`}
                              target='_blank'
                              rel='noopener noreferrer'
                              className='text-xs font-medium text-gray-900 dark:text-gray-100 text-center w-20 line-clamp-2 hover:text-green-600 dark:hover:text-green-400 transition-colors cursor-pointer'
                              onClick={(e) => e.stopPropagation()}
                            >
                              {actor.name}
                            </a>
                            {actor.character && (
                              <p className='text-xs text-gray-500 dark:text-gray-400 text-center w-20 line-clamp-2'>
                                {actor.character}
                              </p>
                            )}
                          </div>
                        ))}
                      </div>
                    </div>
                  ) : (
                    <p className='text-gray-700 dark:text-gray-300'>
                      {detailData.actors
                        .slice(0, 10)
                        .map((a) => a.name)
                        .join(', ')}
                    </p>
                  )}
                </div>
              )}

              {/* 制作信息 */}
              <div className='grid grid-cols-2 gap-4 text-sm'>
                {detailData.countries && detailData.countries.length > 0 && (
                  <div>
                    <h4 className='font-semibold text-gray-900 dark:text-gray-100 mb-1 flex items-center gap-1'>
                      <Globe size={14} />
                      国家/地区
                    </h4>
                    <p className='text-gray-700 dark:text-gray-300'>
                      {detailData.countries.join(', ')}
                    </p>
                  </div>
                )}

                {detailData.languages && detailData.languages.length > 0 && (
                  <div>
                    <h4 className='font-semibold text-gray-900 dark:text-gray-100 mb-1 flex items-center gap-1'>
                      <Tag size={14} />
                      语言
                    </h4>
                    <p className='text-gray-700 dark:text-gray-300'>
                      {detailData.languages.join(', ')}
                    </p>
                  </div>
                )}

                {detailData.releaseDate && (
                  <div>
                    <h4 className='font-semibold text-gray-900 dark:text-gray-100 mb-1 flex items-center gap-1'>
                      <Calendar size={14} />
                      上映日期
                    </h4>
                    <p className='text-gray-700 dark:text-gray-300'>
                      {detailData.releaseDate}
                    </p>
                  </div>
                )}

                {detailData.status && (
                  <div>
                    <h4 className='font-semibold text-gray-900 dark:text-gray-100 mb-1'>
                      状态
                    </h4>
                    <p className='text-gray-700 dark:text-gray-300'>
                      {detailData.status}
                    </p>
                  </div>
                )}
              </div>

              {/* 季度和集数信息（仅TMDB电视剧） */}
              {detailData.mediaType === 'tv' && (
                <div className='mt-6'>
                  {loadingSeasons && (
                    <div className='flex items-center justify-center py-4'>
                      <div className='animate-spin rounded-full h-8 w-8 border-b-2 border-green-500'></div>
                    </div>
                  )}

                  {!loadingSeasons && seasonData && (
                    <>
                      {/* 季度列表 */}
                      {seasonData.seasons.length > 0 && (
                        <div className='mb-6'>
                          <h4 className='text-lg font-semibold text-gray-900 dark:text-gray-100 mb-3'>
                            季度
                          </h4>
                          <div className='grid grid-cols-2 sm:grid-cols-3 gap-3'>
                            {seasonData.seasons.map((season: any) => (
                              <div
                                key={season.id}
                                onClick={() =>
                                  handleSeasonChange(season.season_number)
                                }
                                className={`flex items-center gap-2 p-2 rounded cursor-pointer transition-colors ${
                                  selectedSeason === season.season_number
                                    ? 'bg-green-100 dark:bg-green-900/30 ring-2 ring-green-500'
                                    : 'bg-gray-50 dark:bg-gray-800 hover:bg-gray-100 dark:hover:bg-gray-700'
                                }`}
                              >
                                {season.poster_path && (
                                  <div
                                    className='relative w-12 h-16 rounded overflow-hidden bg-gray-200 dark:bg-gray-700 flex-shrink-0 hover:opacity-80 transition-opacity'
                                    onClick={(e) => {
                                      e.stopPropagation();
                                      handleImageClick(
                                        getTMDBImageUrl(
                                          season.poster_path,
                                          'w500'
                                        )
                                      );
                                    }}
                                  >
                                    <ProxyImage
                                      originalSrc={getTMDBImageUrl(
                                        season.poster_path,
                                        'w92'
                                      )}
                                      alt={season.name}
                                      className='absolute inset-0 w-full h-full object-cover'
                                      draggable={false}
                                    />
                                  </div>
                                )}
                                <div className='flex-1 min-w-0'>
                                  <p className='text-sm font-medium text-gray-900 dark:text-gray-100 truncate'>
                                    {season.name}
                                  </p>
                                  <p className='text-xs text-gray-500 dark:text-gray-400'>
                                    {season.episode_count} 集
                                  </p>
                                </div>
                              </div>
                            ))}
                          </div>
                        </div>
                      )}

                      {/* 集数列表 */}
                      {seasonData.episodes.length > 0 && (
                        <div>
                          <h4 className='text-lg font-semibold text-gray-900 dark:text-gray-100 mb-3'>
                            {seasonData.seasons.find(
                              (s: any) => s.season_number === selectedSeason
                            )?.name || `第${selectedSeason}季`}
                          </h4>
                          <div
                            ref={episodesScrollRef}
                            onMouseDown={handleMouseDown}
                            onMouseMove={handleMouseMove}
                            onMouseUp={handleMouseUp}
                            onMouseLeave={handleMouseLeave}
                            className='overflow-x-auto -mx-6 px-6 cursor-grab active:cursor-grabbing'
                            style={{
                              scrollbarWidth: 'thin',
                              scrollBehavior: isDragging ? 'auto' : 'smooth',
                            }}
                          >
                            <div className='flex gap-3 py-2'>
                              {seasonData.episodes.map((episode: Episode) => {
                                const isExpanded = expandedEpisodes.has(
                                  episode.id
                                );
                                const isCurrentEpisode =
                                  currentEpisode === episode.episode_number;
                                return (
                                  <div
                                    key={episode.id}
                                    id={`episode-${episode.episode_number}`}
                                    className={`flex-shrink-0 w-64 p-3 rounded ${
                                      isCurrentEpisode
                                        ? 'bg-green-100 dark:bg-green-900/30 ring-2 ring-green-500'
                                        : 'bg-gray-50 dark:bg-gray-800'
                                    }`}
                                    style={{
                                      pointerEvents: isDragging
                                        ? 'none'
                                        : 'auto',
                                    }}
                                  >
                                    {episode.still_path && (
                                      <div
                                        className='relative w-full h-36 rounded overflow-hidden bg-gray-200 dark:bg-gray-700 mb-2 cursor-pointer hover:opacity-90 transition-opacity'
                                        onClick={() =>
                                          handleImageClick(
                                            getTMDBImageUrl(
                                              episode.still_path,
                                              'w500'
                                            )
                                          )
                                        }
                                      >
                                        <ProxyImage
                                          originalSrc={getTMDBImageUrl(
                                            episode.still_path,
                                            'w300'
                                          )}
                                          alt={episode.name}
                                          className='absolute inset-0 w-full h-full object-cover'
                                          draggable={false}
                                        />
                                      </div>
                                    )}
                                    <p className='text-sm font-medium text-gray-900 dark:text-gray-100 mb-1'>
                                      第{episode.episode_number}集:{' '}
                                      {episode.name}
                                    </p>
                                    {episode.overview && (
                                      <p
                                        onClick={() => {
                                          const newExpanded = new Set(
                                            expandedEpisodes
                                          );
                                          if (isExpanded) {
                                            newExpanded.delete(episode.id);
                                          } else {
                                            newExpanded.add(episode.id);
                                          }
                                          setExpandedEpisodes(newExpanded);
                                        }}
                                        className={`text-xs text-gray-600 dark:text-gray-400 cursor-pointer ${
                                          isExpanded ? '' : 'line-clamp-3'
                                        }`}
                                      >
                                        {episode.overview}
                                      </p>
                                    )}
                                    {episode.air_date && (
                                      <p className='text-xs text-gray-500 dark:text-gray-500 mt-1'>
                                        {episode.air_date}
                                      </p>
                                    )}
                                  </div>
                                );
                              })}
                            </div>
                          </div>
                        </div>
                      )}
                    </>
                  )}
                </div>
              )}

              {/* 数据源显示和切换 */}
              <div className='mt-6 pt-4 border-t border-gray-200 dark:border-gray-700'>
                <div className='flex items-center justify-between'>
                  <div className='flex items-center gap-2'>
                    <span className='text-sm text-gray-500 dark:text-gray-400'>
                      数据来源:
                    </span>
                    <span className='text-sm font-medium text-gray-700 dark:text-gray-300 uppercase'>
                      {currentSource === 'douban' && 'Douban'}
                      {currentSource === 'bangumi' && 'Bangumi'}
                      {currentSource === 'cms' && 'CMS'}
                      {currentSource === 'tmdb' && 'TMDB'}
                    </span>
                  </div>
                  {currentSource !== 'tmdb' && (
                    <button
                      onClick={handleToggleSource}
                      disabled={loading}
                      className='px-3 py-1.5 text-sm rounded-lg bg-green-500 hover:bg-green-600 text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed'
                    >
                      切换到 TMDB
                    </button>
                  )}
                  {currentSource === 'tmdb' &&
                    originalSource !== 'tmdb' &&
                    originalDetailData && (
                      <button
                        onClick={handleToggleSource}
                        disabled={loading}
                        className='px-3 py-1.5 text-sm rounded-lg bg-gray-500 hover:bg-gray-600 text-white transition-colors disabled:opacity-50 disabled:cursor-not-allowed'
                      >
                        切换回{' '}
                        {originalSource === 'douban'
                          ? 'Douban'
                          : originalSource === 'bangumi'
                          ? 'Bangumi'
                          : 'CMS'}
                      </button>
                    )}
                </div>
              </div>
            </div>
          )}
        </div>
      </div>

      {/* 图片查看器 */}
      {galleryModal}
      {showImageViewer && (
        <ImageViewer
          isOpen={showImageViewer}
          onClose={() => setShowImageViewer(false)}
          imageUrl={selectedImage}
          alt={detailData?.title || title}
        />
      )}
    </div>
  );

  return createPortal(content, document.body);
};

export default DetailPanel;
