'use client'; import { useState, useEffect } from 'react'; import Image from 'next/image'; import { useRouter, useSearchParams } from 'next/navigation'; import { createClient } from '@/lib/supabase/client'; import { Play } from 'lucide-react'; import { MovieDetail, getSources, generateStreamLink, getRecommendations, Subject } from '@/lib/api'; import VideoPlayer from './VideoPlayer'; import MovieRow from './MovieRow'; import BookmarkButton from './BookmarkButton'; interface MovieDetailViewProps { detail: MovieDetail; } export default function MovieDetailView({ detail }: MovieDetailViewProps) { const { subject, resource } = detail; const isSeries = subject.subjectType === 2; // Series State const [selectedSeason, setSelectedSeason] = useState(isSeries && resource?.seasons?.[0]?.se || 0); const [selectedEpisode, setSelectedEpisode] = useState(1); // Player State const [isPlaying, setIsPlaying] = useState(false); const [streamUrl, setStreamUrl] = useState(null); const [captions, setCaptions] = useState([]); // Use appropriate type if imported or allow implicit const [loading, setLoading] = useState(false); const [error, setError] = useState(''); // Recommendations State const [recommendations, setRecommendations] = useState([]); const currentSeason = resource?.seasons?.find(s => s.se === selectedSeason); const episodeCount = currentSeason?.maxEp || 0; const [sources, setSources] = useState([]); const [currentQuality, setCurrentQuality] = useState(0); const [historyResume, setHistoryResume] = useState<{ episode?: number; season?: number; position?: number } | null>(null); const router = useRouter(); const supabase = createClient(); useEffect(() => { const fetchRecs = async () => { if (subject?.subjectId) { try { const recs = await getRecommendations(subject.subjectId); setRecommendations(recs); } catch (e) { console.error("Failed to fetch recommendations", e); } } }; fetchRecs(); }, [subject?.subjectId]); const searchParams = useSearchParams(); useEffect(() => { const fetchHistory = async () => { if (!subject?.subjectId) return; const { data: { user } } = await supabase.auth.getUser(); if (!user) return; const { data, error } = await supabase .from('history') .select('*') .eq('user_id', user.id) .eq('subject_id', subject.subjectId) .single(); if (data) { setHistoryResume({ episode: data.episode || 1, season: data.season || 0, position: data.last_position }); if (isSeries) { if (data.season) setSelectedSeason(data.season); if (data.episode) setSelectedEpisode(data.episode); } // Autoplay after history is set const autoplay = searchParams?.get('autoplay'); if (autoplay === 'true') { // Small delay to ensure state is committed setTimeout(() => { handlePlay(data.season || 0, data.episode || 1); }, 500); } } }; fetchHistory(); }, [subject?.subjectId, isSeries, searchParams]); const handlePlay = async (sOverride?: number, eOverride?: number) => { // Check Auth const { data: { user } } = await supabase.auth.getUser(); if (!user) { router.push('/login'); return; } if (isPlaying) return; setLoading(true); setError(''); try { // Fetch Source const s = sOverride !== undefined ? sOverride : (isSeries ? selectedSeason : 0); const e = eOverride !== undefined ? eOverride : (isSeries ? selectedEpisode : 0); // ... rest of logic const data = await getSources(subject.subjectId, subject.detailPath, s, e); const { sources: fetchedSources, captions: fetchedCaptions } = data; if (!fetchedSources || fetchedSources.length === 0) { throw new Error("Source not found"); } // Pick best quality (max resolution) const sorted = fetchedSources.sort((a, b) => b.resolution - a.resolution); const bestSource = sorted[0]; if (!bestSource || !bestSource.url) { throw new Error("Playable URL not found"); } // Generate Link const link = await generateStreamLink(bestSource.url); if (!link) throw new Error("Stream link generation failed"); setSources(sorted); setStreamUrl(link); setCaptions(fetchedCaptions); setCurrentQuality(bestSource.resolution); setIsPlaying(true); } catch (err) { console.error(err); setError("Failed to load video. Please try again."); } finally { setLoading(false); } }; const changeQuality = async (source: any) => { try { const link = await generateStreamLink(source.url); if (link) { setStreamUrl(link); setCurrentQuality(source.resolution); } } catch (e) { console.error("Failed to change quality", e); } }; return (
{/* Background Image / Backdrop */}
{subject.title}
{/* Content */}
{/* Poster */}
{subject.title}
{/* Details */}

{subject.title}

{subject.releaseDate} HD {subject.genre} {subject.duration ? `${Math.round(subject.duration / 60)}m` : ''} {subject.countryName && • {subject.countryName}} {subject.imdbRatingValue && ( ⭐ {subject.imdbRatingValue} )}
{/* Controls */}
{isSeries && (
Season
Episode: {selectedEpisode}
{Array.from({ length: episodeCount }, (_, i) => episodeCount - i).map(ep => ( ))}
)}
{error && (

{error}

)}

{subject.description}

{/* Cast and More Info */}
{detail.stars && detail.stars.length > 0 && (

Cast

{detail.stars.map((star: any, index: number) => (
{star.avatarUrl || star.avatar || star.image ? ( {star.name} ) : null} {star.name} {star.character && as {star.character}}
))}
)}
{/* Recommendations */} {recommendations.length > 0 && (
)} {isPlaying && streamUrl && ( setIsPlaying(false)} // History Data subjectId={subject.subjectId} type={isSeries ? 'series' : 'movie'} title={subject.title} poster={subject.cover?.url || subject.image?.url || ''} season={isSeries ? selectedSeason : undefined} episode={isSeries ? selectedEpisode : undefined} startTime={(historyResume?.season === selectedSeason && historyResume?.episode === selectedEpisode) || (!isSeries && historyResume) ? historyResume?.position : 0} /> )}
); }