import React, { useState, useEffect, useRef, Suspense, lazy, useMemo, useCallback } from "react";
import type { RefObject } from "react";
import type { Id } from "react-toastify";
import { toast } from "react-toastify";
import { Button } from "@mui/joy";
import { Accordion, AccordionTab } from "primereact/accordion";
import { AutoComplete } from "primereact/autocomplete";
import { authFetch, doRefresh } from "@/utils/authFetch";
import { useAutoCompleteScrollFix } from '@/hooks/useAutoCompleteScrollFix';
import BreadcrumbNav from "./BreadcrumbNav";
import { API_URL, ENVIRONMENT } from "@/config";
import "./RequestManagement.css";

interface Artist {
    id: string | number;
    name: string;
    artist?: string;
}

interface Album {
    id: string | number;
    title: string;
    album?: string;
    release_date?: string;
    cover_image?: string;
    cover_small?: string;
    tracks?: Track[];
}

interface FetchTracksSequentiallyFn {
    (): Promise<void>;
    lastCall?: number;
}

interface Track {
    id: string | number;
    title: string;
    artist?: string;
    duration?: number | string;
    album_id?: string | number;
    track_number?: number;
    version?: string;
}

interface Video {
    id: string | number;
    title: string;
    name?: string; // Alternative to title
    artist?: string;
    artistId?: string | number;
    artist_id?: string | number; // snake_case variant
    duration?: number | string;
    image?: string;
    imageUrl?: string;
    image_url?: string; // snake_case variant
    cover?: string;
    thumbnail?: string;
    releaseDate?: string;
    release_date?: string; // snake_case variant
}

interface DiskSpaceInfo {
    total?: number;
    used?: number;
    available?: number;
    percent?: number;
    usedPercent?: number;
    availableFormatted?: string;
}

interface AudioProgress {
    current: number;
    duration: number;
}

interface SearchArtistsFn {
    (e: { query: string }): void;
    lastCall?: number;
}

export default function MediaRequestForm() {
    const [type, setType] = useState("artist");
    const [selectedArtist, setSelectedArtist] = useState<Artist | null>(null);
    const [artistInput, setArtistInput] = useState("");
    const [albumInput, setAlbumInput] = useState("");
    const [trackInput, setTrackInput] = useState("");
    const [quality, setQuality] = useState("FLAC"); // default FLAC
    const [selectedItem, setSelectedItem] = useState<Artist | Album | Track | null>(null);
    const [albums, setAlbums] = useState<Album[]>([]);
    const [tracksByAlbum, setTracksByAlbum] = useState<Record<string | number, Track[]>>({});
    const [selectedTracks, setSelectedTracks] = useState<Record<string | number, string[] | null>>({});
    const [artistSuggestions, setArtistSuggestions] = useState<Artist[]>([]);
    const [isSubmitting, setIsSubmitting] = useState(false);
    const [isSearching, setIsSearching] = useState(false);
    const [loadingAlbumId, setLoadingAlbumId] = useState<string | number | null>(null);
    const [expandedAlbums, setExpandedAlbums] = useState<number[]>([]);
    const [isFetching, setIsFetching] = useState(false);
    const [currentTrackId, setCurrentTrackId] = useState<string | number | null>(null);
    const [isAudioPlaying, setIsAudioPlaying] = useState(false);
    const [audioLoadingTrackId, setAudioLoadingTrackId] = useState<string | number | null>(null);
    const [playbackQueue, setPlaybackQueue] = useState<Track[]>([]);
    const [queueIndex, setQueueIndex] = useState<number | null>(null);
    const [queueAlbumId, setQueueAlbumId] = useState<string | number | null>(null);
    const [albumPlaybackLoadingId, setAlbumPlaybackLoadingId] = useState<string | number | null>(null);
    const [shuffleAlbums, setShuffleAlbums] = useState<Record<string | number, boolean>>({});
    const [audioProgress, setAudioProgress] = useState<AudioProgress>({ current: 0, duration: 0 });
    const [diskSpace, setDiskSpace] = useState<DiskSpaceInfo | null>(null);

    // Video search state
    const [videoSearchQuery, setVideoSearchQuery] = useState("");
    const [videoResults, setVideoResults] = useState<Video[]>([]);
    const [isVideoSearching, setIsVideoSearching] = useState(false);
    const [selectedVideos, setSelectedVideos] = useState<Set<string | number>>(new Set());
    const [videoPreviewId, setVideoPreviewId] = useState<string | number | null>(null);
    const [videoStreamUrl, setVideoStreamUrl] = useState<string | null>(null);
    const [isVideoLoading, setIsVideoLoading] = useState(false);
    const [videoDownloadProgress, setVideoDownloadProgress] = useState<number>(0); // 0-100
    const [showVideoSection, setShowVideoSection] = useState(false);
    const videoAbortRef = useRef<AbortController | null>(null);

    const resetVideoState = () => {
        videoAbortRef.current?.abort();
        if (videoStreamUrl?.startsWith("blob:")) URL.revokeObjectURL(videoStreamUrl);
        setVideoResults([]);
        setSelectedVideos(new Set());
        setVideoPreviewId(null);
        setVideoStreamUrl(null);
        setVideoSearchQuery("");
        setVideoDownloadProgress(0);
        setIsVideoLoading(false);
    };

    const { attachScrollFix, cleanupScrollFix } = useAutoCompleteScrollFix();

    const debounceTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
    const autoCompleteRef = useRef<any>(null);
    const metadataFetchToastId = useRef<Id | null>(null);
    const audioRef = useRef<HTMLAudioElement | null>(null);
    const audioSourcesRef = useRef<Record<string | number, string>>({});
    const pendingTrackFetchesRef = useRef<Record<string | number, Promise<string>>>({});
    const playbackQueueRef = useRef<Track[]>([]);
    const queueIndexRef = useRef<number | null>(null);
    const queueAlbumIdRef = useRef<string | number | null>(null);
    const albumHeaderRefs = useRef<Record<string | number, HTMLElement | null>>({});
    const suppressHashRef = useRef(false);
    const lastUrlRef = useRef("");
    const playPauseClickRef = useRef(false);

    const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); // Helper for delays
    const sanitizeFilename = (text: string) => (text || "").replace(/[\\/:*?"<>|]/g, "_") || "track";
    const formatTime = (seconds: number) => {
        if (!Number.isFinite(seconds) || seconds < 0) return "0:00";
        const mins = Math.floor(seconds / 60);
        const secs = Math.floor(seconds % 60)
            .toString()
            .padStart(2, "0");
        return `${mins}:${secs}`;
    };

    useEffect(() => {
        if (typeof window === "undefined") return;
        lastUrlRef.current = window.location.pathname + window.location.search + window.location.hash;
    }, []);

    // Fetch disk space on mount
    useEffect(() => {
        const fetchDiskSpace = async () => {
            try {
                const res = await fetch('/api/disk-space');
                if (res.ok) {
                    const data = await res.json();
                    setDiskSpace(data);
                }
            } catch (err) {
                console.error('Failed to fetch disk space:', err);
            }
        };
        fetchDiskSpace();
    }, []);

    useEffect(() => {
        if (typeof window === "undefined") return undefined;

        const handleHashChange = () => {
            if (suppressHashRef.current) {
                const fallback =
                    lastUrlRef.current || window.location.pathname + window.location.search;
                if (typeof window.history?.replaceState === "function") {
                    window.history.replaceState(null, "", fallback);
                }
                lastUrlRef.current = fallback;
                suppressHashRef.current = false;
            } else {
                lastUrlRef.current =
                    window.location.pathname + window.location.search + window.location.hash;
            }
        };

        window.addEventListener("hashchange", handleHashChange);
        return () => window.removeEventListener("hashchange", handleHashChange);
    }, []);


    const Spinner = () => (
        <span
            className="inline-block ml-2 h-4 w-4 border-2 border-t-2 border-gray-300 border-t-blue-600 rounded-full animate-spin"
            aria-label="Loading"
        />
    );

    const InlineSpinner = ({ sizeClass = "h-3 w-3" }) => (
        <span
            className={`inline-block ${sizeClass} border-2 border-t-2 border-gray-300 border-t-blue-600 rounded-full animate-spin`}
            aria-label="Loading audio"
        />
    );

    const PlayIcon = () => (
        <svg viewBox="0 0 24 24" role="presentation" className="w-4 h-4" aria-hidden="true">
            <path fill="currentColor" d="M8 5v14l11-7z" />
        </svg>
    );

    const PauseIcon = () => (
        <svg viewBox="0 0 24 24" role="presentation" className="w-4 h-4" aria-hidden="true">
            <path fill="currentColor" d="M6 5h4v14H6zm8 0h4v14h-4z" />
        </svg>
    );

    const ShuffleIcon = ({ active }: { active: boolean }) => (
        <svg
            viewBox="0 0 24 24"
            role="presentation"
            className={`w-4 h-4 ${active ? "text-blue-600" : "text-neutral-500"}`}
            aria-hidden="true"
        >
            <path
                fill="currentColor"
                d="M17 3h4v4h-2V6.41l-4.29 4.3-1.42-1.42L17.59 5H17V3zm0 11h-1.59l-2.7-2.7 1.42-1.42 2.99 3h1.88v-1.59L21 14l-3.99 3V15zm-7.12-1.71L4.41 5H3V3h2.59l6.12 6.12-1.71 1.17zM3 19v-2h1.41l4.7-4.7 1.42 1.41L6.41 19H3z"
            />
        </svg>
    );

    const shuffleArray = <T,>(arr: T[]): T[] => {
        const clone = [...arr];
        for (let i = clone.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [clone[i], clone[j]] = [clone[j], clone[i]];
        }
        return clone;
    };

    const ensureAlbumExpanded = (albumIndex: number) => {
        if (typeof albumIndex !== "number") return;
        let albumAdded = false;
        setExpandedAlbums((prev) => {
            const current = Array.isArray(prev) ? [...prev] : [];
            if (current.includes(albumIndex)) return prev;

            if (typeof window !== "undefined") {
                lastUrlRef.current = window.location.pathname + window.location.search + window.location.hash;
            }

            suppressHashRef.current = true;
            current.push(albumIndex);
            albumAdded = true;
            return current;
        });

        if (albumAdded) {
            setTimeout(() => {
                suppressHashRef.current = false;
            }, 400);
        }
    };

    const resetQueueState = () => {
        setPlaybackQueue([]);
        playbackQueueRef.current = [];
        setQueueIndex(null);
        queueIndexRef.current = null;
        setQueueAlbumId(null);
        queueAlbumIdRef.current = null;
        setAlbumPlaybackLoadingId(null);
        setAudioProgress({ current: 0, duration: 0 });
    };

    const getTrackSource = async (trackId: string | number): Promise<string> => {
        if (audioSourcesRef.current[trackId]) {
            return audioSourcesRef.current[trackId];
        }

        if (!pendingTrackFetchesRef.current[trackId]) {
            pendingTrackFetchesRef.current[trackId] = (async () => {
                const res = await authFetch(`${API_URL}/trip/get_track_by_id/${trackId}?quality=${quality}`);
                if (!res.ok) throw new Error("Failed to fetch track URL");
                const data = await res.json();

                if (!data.stream_url) {
                    throw new Error("No stream URL returned for this track.");
                }

                const fileResponse = await fetch(data.stream_url, {
                    method: "GET",
                    mode: "cors",
                    credentials: "omit",
                });

                if (!fileResponse.ok) {
                    throw new Error(`Failed to fetch track file: ${fileResponse.status}`);
                }

                const blob = await fileResponse.blob();
                const sourceUrl = URL.createObjectURL(blob);

                if (audioSourcesRef.current[trackId]) {
                    URL.revokeObjectURL(audioSourcesRef.current[trackId]);
                }

                audioSourcesRef.current[trackId] = sourceUrl;
                return sourceUrl;
            })().finally(() => {
                delete pendingTrackFetchesRef.current[trackId];
            });
        }

        return pendingTrackFetchesRef.current[trackId];
    };

    const prefetchTrack = async (track: Track | null) => {
        if (!track || audioSourcesRef.current[track.id]) {
            return;
        }
        // Check if already being fetched (returns a truthy promise)
        if (track.id in pendingTrackFetchesRef.current) {
            return;
        }
        try {
            await getTrackSource(track.id);
        } catch (error) {
            console.error("Prefetch failed", error);
        }
    };

    const playTrack = async (track: Track, { fromQueue = false } = {}) => {
        const audio = audioRef.current;
        if (!audio || !track) return;

        if (!fromQueue) {
            resetQueueState();
        }

        setAudioLoadingTrackId(track.id);
        try {
            const sourceUrl = await getTrackSource(track.id);
            audio.pause();
            audio.currentTime = 0;
            audio.src = sourceUrl;
            setAudioProgress({ current: 0, duration: 0 });
            setCurrentTrackId(track.id);
            setIsAudioPlaying(true);
            await audio.play();
        } catch (error) {
            setIsAudioPlaying(false);
            console.error(error);
            toast.error("Failed to play track.");
            if (!fromQueue) {
                resetQueueState();
            }
        } finally {
            setAudioLoadingTrackId(null);
        }
    };

    // Fetch artist suggestions for autocomplete
    const searchArtists: SearchArtistsFn = (e) => {
        const query = e.query.trim();
        if (!query) {
            setArtistSuggestions([]);
            setSelectedArtist(null);
            return;
        }

        if (debounceTimeout.current) clearTimeout(debounceTimeout.current);

        debounceTimeout.current = setTimeout(async () => {
            try {
                // Ensure at least 600ms between actual requests
                const now = Date.now();
                if (!searchArtists.lastCall) searchArtists.lastCall = 0;
                const elapsed = now - searchArtists.lastCall;
                const minDelay = 600; // ms
                if (elapsed < minDelay) await delay(minDelay - elapsed);

                searchArtists.lastCall = Date.now();

                const res = await authFetch(
                    `${API_URL}/trip/get_artists_by_name?artist=${encodeURIComponent(query)}&group=true`
                );
                if (!res.ok) throw new Error("API error");
                const data = await res.json();
                setArtistSuggestions(data);
            } catch (err) {
                toast.error("Failed to fetch artist suggestions.");
                setArtistSuggestions([]);
            }
        }, 500); // debounce 500ms
    };


    const truncate = (text: string, maxLen: number) =>
        maxLen <= 3
            ? text.slice(0, maxLen)
            : text.length <= maxLen
                ? text
                : text.slice(0, maxLen - 3) + '...';

    const selectArtist = (artist: Artist) => {
        // artist may be a grouped item or an alternate object
        const value = artist.artist || artist.name || "";
        setSelectedArtist(artist);
        setArtistInput(value);
        setArtistSuggestions([]);

        // Hide autocomplete panel and blur input to prevent leftover white box.
        // Use a small timeout so PrimeReact internal handlers can finish first.
        try {
            const ac = autoCompleteRef.current;
            // Give PrimeReact a tick to finish its events, then call hide().
            setTimeout(() => {
                try {
                    if (ac && typeof ac.hide === "function") {
                        ac.hide();
                    }

                    // If panel still exists, hide it via style (safer than removing the node)
                    setTimeout(() => {
                        const panel = document.querySelector('.p-autocomplete-panel') as HTMLElement | null;
                        if (panel) {
                            panel.style.display = 'none';
                            panel.style.opacity = '0';
                            panel.style.visibility = 'hidden';
                            panel.style.pointerEvents = 'none';
                        }
                    }, 10);

                    // blur the input element if present
                    const inputEl = ac?.getInput ? ac.getInput() : document.querySelector('.p-autocomplete-input') as HTMLInputElement | null;
                    if (inputEl && typeof inputEl.blur === 'function') inputEl.blur();
                } catch (innerErr) {
                    // Ignore inner errors
                }
            }, 0);
        } catch (err) {
            // Ignore outer errors
        }
    };

    const totalAlbums = albums.length;
    const totalTracks = useMemo(() =>
        Object.values(tracksByAlbum).reduce((sum: number, arr) => (Array.isArray(arr) ? sum + arr.length : sum), 0),
        [tracksByAlbum]
    );

    const artistItemTemplate = (artist: Artist & { alternatives?: Artist[]; alternates?: Artist[] }) => {
        if (!artist) return null;

        const alts = artist.alternatives || artist.alternates || [];

        return (
            <div className="py-1">
                <div className="font-medium flex items-baseline gap-2">
                    <span>{truncate(artist.artist || artist.name, 58)}</span>
                    <span className="text-xs text-neutral-400">ID: {artist.id}</span>
                </div>
                {alts.length > 0 && (
                    <div className="text-xs text-neutral-500 mt-1">
                        <div className="flex flex-wrap gap-2 items-center">
                            <span className="mr-1">Alternates:</span>
                            {alts.map((alt, idx) => (
                                <span key={alt.id || idx} className="inline-flex items-center max-w-[200px] truncate">
                                    <button
                                        type="button"
                                        onClick={(e) => {
                                            e.stopPropagation();
                                            selectArtist({ ...alt, artist: alt.artist || alt.name });
                                        }}
                                        className="ml-1 mr-1 underline hover:text-blue-600 bg-transparent border-none p-0 cursor-pointer"
                                    >
                                        {truncate(alt.artist || alt.name, 26)}
                                    </button>
                                    <span className="text-xs text-neutral-400">ID: {alt.id}</span>
                                    {idx < alts.length - 1 ? <span className="mx-1">,</span> : null}
                                </span>
                            ))}
                        </div>
                    </div>
                )}
            </div>
        );
    };


    // Handle autocomplete input changes (typing/selecting)
    const handleArtistChange = (e: { value: string | Artist }) => {
        if (typeof e.value === "string") {
            setArtistInput(e.value);
            setSelectedArtist(null);
        } else if (e.value && typeof e.value === "object") {
            setSelectedArtist(e.value);
            setArtistInput(e.value.artist || e.value.name || "");
        } else {
            setArtistInput("");
            setSelectedArtist(null);
        }
    };

    // Search button click handler
    const handleSearch = async () => {
        toast.dismiss();
        setIsSearching(true);
        resetQueueState();
        const videosWereOpen = showVideoSection;
        resetVideoState();
        setShuffleAlbums({});
        if (audioRef.current) {
            audioRef.current.pause();
            audioRef.current.removeAttribute("src");
            audioRef.current.load();
        }
        setIsAudioPlaying(false);
        setAudioLoadingTrackId(null);
        setCurrentTrackId(null);
        try {
            if (metadataFetchToastId.current) toast.dismiss(metadataFetchToastId.current);
        } catch (err) {
        }
        metadataFetchToastId.current = toast.info("Retrieving metadata...",
            {
                autoClose: false,
                progress: 0,
                closeOnClick: false,
            }
        );
        if (type === "artist") {
            if (!selectedArtist) {
                toast.error("Please select a valid artist from suggestions.");
                setIsSearching(false);
                return;
            }

            setSelectedItem({ ...selectedArtist, name: selectedArtist.artist || selectedArtist.name || "" });

            try {
                const res = await authFetch(
                    `${API_URL}/trip/get_albums_by_artist_id/${selectedArtist.id}?quality=${quality}`
                );
                if (!res.ok) throw new Error("API error");
                const data = await res.json();

                data.sort((a, b) =>
                    (b.release_date || "").localeCompare(a.release_date || "")
                );

                setAlbums(data);
                setShuffleAlbums({});
                setTracksByAlbum({});
                setExpandedAlbums([]);

                // Set selectedTracks for all albums as null (means tracks loading/not loaded)
                setSelectedTracks(
                    data.reduce((acc, album) => {
                        acc[album.id] = null;
                        return acc;
                    }, {})
                );

                // If the video section was open before, auto-fetch videos for the new artist
                if (videosWereOpen && selectedArtist) {
                    fetchArtistVideos(selectedArtist.id);
                }
            } catch (err) {
                toast.error("Failed to fetch albums for artist.");
                setAlbums([]);
                setTracksByAlbum({});
                setSelectedTracks({});
            }
        } else if (type === "album") {
            if (!artistInput.trim() || !albumInput.trim()) {
                toast.error("Artist and Album are required.");
                setIsSearching(false);
                return;
            }
            setSelectedItem({ id: 0, name: `${artistInput} - ${albumInput}` });
            setAlbums([]);
            setTracksByAlbum({});
            setSelectedTracks({});
        } else if (type === "track") {
            if (!artistInput.trim() || !trackInput.trim()) {
                toast.error("Artist and Track are required.");
                setIsSearching(false);
                return;
            }
            setSelectedItem({ id: 0, name: `${artistInput} - ${trackInput}` });
            setAlbums([]);
            setTracksByAlbum({});
            setSelectedTracks({});
        }
        setIsSearching(false);
    };

    const handleTrackPlayPause = async (track: Track, albumId: string | number | null = null, albumIndex: number | null = null) => {
        // Prevent double-clicks / rapid clicks
        if (playPauseClickRef.current) return;
        playPauseClickRef.current = true;

        const audio = audioRef.current;
        if (!audio) {
            playPauseClickRef.current = false;
            return;
        }

        if (typeof albumIndex === "number") {
            ensureAlbumExpanded(albumIndex);
        }

        try {
            if (currentTrackId === track.id) {
                if (audio.paused) {
                    setIsAudioPlaying(true);
                    await audio.play();
                } else {
                    setIsAudioPlaying(false);
                    audio.pause();
                }
            } else {
                await playTrack(track, { fromQueue: false });
            }
        } catch (error) {
            setIsAudioPlaying(false);
            console.error(error);
            toast.error("Unable to play/pause track.");
        } finally {
            // Small delay before allowing next click to prevent rapid clicks
            setTimeout(() => {
                playPauseClickRef.current = false;
            }, 150);
        }
    };

    const toggleAlbumShuffle = (albumId) => {
        setShuffleAlbums((prev) => ({ ...prev, [albumId]: !prev[albumId] }));
    };

    const startAlbumPlayback = async (albumId, albumIndex) => {
        const tracks = tracksByAlbum[albumId];
        if (!Array.isArray(tracks) || tracks.length === 0) {
            toast.error("Tracks are still loading for this album.");
            return;
        }

        ensureAlbumExpanded(albumIndex);

        const shouldShuffle = !!shuffleAlbums[albumId];
        const queue = shouldShuffle ? shuffleArray(tracks) : [...tracks];
        setPlaybackQueue(queue);
        playbackQueueRef.current = queue;
        setQueueAlbumId(albumId);
        queueAlbumIdRef.current = albumId;
        setQueueIndex(0);
        queueIndexRef.current = 0;
        setAlbumPlaybackLoadingId(albumId);

        try {
            await playTrack(queue[0], { fromQueue: true });
            setAlbumPlaybackLoadingId(null);
            if (queue[1]) prefetchTrack(queue[1]);
        } catch (err) {
            setAlbumPlaybackLoadingId(null);
        }
    };

    const handleAlbumPlayPause = async (albumId, albumIndex) => {
        const audio = audioRef.current;
        if (!audio) return;

        ensureAlbumExpanded(albumIndex);

        if (queueAlbumId === albumId && playbackQueue.length > 0) {
            if (audio.paused) {
                setIsAudioPlaying(true);
                try {
                    await audio.play();
                } catch (error) {
                    setIsAudioPlaying(false);
                    console.error(error);
                    toast.error("Unable to resume album playback.");
                }
            } else {
                setIsAudioPlaying(false);
                audio.pause();
            }
            return;
        }

        await startAlbumPlayback(albumId, albumIndex);
    };

    const handleTrackDownload = async (track) => {
        try {
            const res = await authFetch(`${API_URL}/trip/get_track_by_id/${track.id}?quality=${quality}`);
            if (!res.ok) throw new Error("Failed to fetch track URL");
            const data = await res.json();

            if (!data.stream_url) {
                throw new Error("No stream URL returned for this track.");
            }

            const fileResponse = await fetch(data.stream_url, {
                method: "GET",
                mode: "cors",
                credentials: "omit",
            });

            if (!fileResponse.ok) {
                throw new Error(`Failed to fetch track file: ${fileResponse.status}`);
            }

            const blob = await fileResponse.blob();
            const url = URL.createObjectURL(blob);
            const artistName = track.artist || selectedArtist?.artist || selectedArtist?.name || "Unknown Artist";
            const urlPath = new URL(data.stream_url).pathname;
            const extension = urlPath.split(".").pop()?.split("?")[0] || "flac";
            const filename = `${sanitizeFilename(artistName)} - ${sanitizeFilename(track.title)}.${extension}`;

            const link = document.createElement("a");
            link.href = url;
            link.download = filename;
            document.body.appendChild(link);
            link.click();
            link.remove();
            URL.revokeObjectURL(url);
        } catch (error) {
            console.error(error);
            toast.error("Failed to download track.");
        }
    };

    // ========================
    // VIDEO SEARCH & PLAYBACK
    // ========================

    const searchVideos = async () => {
        const query = videoSearchQuery.trim();
        if (!query) {
            toast.error("Please enter a search query.");
            return;
        }

        setIsVideoSearching(true);
        setVideoResults([]);
        setSelectedVideos(new Set());
        setVideoPreviewId(null);
        setVideoStreamUrl(null);

        try {
            const res = await authFetch(
                `${API_URL}/trip/videos/search?q=${encodeURIComponent(query)}&limit=50`
            );
            if (!res.ok) throw new Error("API error");
            const data = await res.json();
            setVideoResults(Array.isArray(data) ? data : data.videos || []);
        } catch (err) {
            console.error(err);
            toast.error("Failed to search for videos.");
            setVideoResults([]);
        } finally {
            setIsVideoSearching(false);
        }
    };

    const fetchArtistVideos = async (artistId: string | number) => {
        setIsVideoSearching(true);
        setVideoResults([]);
        setSelectedVideos(new Set());
        setVideoPreviewId(null);
        setVideoStreamUrl(null);
        setShowVideoSection(true);

        try {
            const res = await authFetch(`${API_URL}/trip/videos/artist/${artistId}`);
            if (!res.ok) throw new Error("API error");
            const data = await res.json();
            setVideoResults(Array.isArray(data) ? data : data.videos || []);
        } catch (err) {
            console.error(err);
            toast.error("Failed to fetch artist videos.");
            setVideoResults([]);
        } finally {
            setIsVideoSearching(false);
        }
    };

    const toggleVideoSelection = (videoId: string | number) => {
        setSelectedVideos((prev) => {
            const next = new Set(prev);
            if (next.has(videoId)) {
                next.delete(videoId);
            } else {
                next.add(videoId);
            }
            return next;
        });
    };

    const handleVideoPreview = async (video: Video) => {
        if (videoPreviewId === video.id) {
            // Already previewing this video — toggle off
            videoAbortRef.current?.abort();
            if (videoStreamUrl?.startsWith("blob:")) URL.revokeObjectURL(videoStreamUrl);
            setVideoPreviewId(null);
            setVideoStreamUrl(null);
            setVideoDownloadProgress(0);
            return;
        }

        // Abort any in-flight preview download
        videoAbortRef.current?.abort();
        if (videoStreamUrl?.startsWith("blob:")) URL.revokeObjectURL(videoStreamUrl);

        const abort = new AbortController();
        videoAbortRef.current = abort;

        setVideoPreviewId(video.id);
        setVideoStreamUrl(null);
        setIsVideoLoading(true);
        setVideoDownloadProgress(0);

        // Use XMLHttpRequest instead of fetch to avoid tying up a fetch
        // connection slot — the browser limits concurrent fetch connections
        // per origin (~6), and a long video download via ReadableStream
        // would starve the sequential track metadata fetches.
        const doXhr = (retry: boolean): Promise<void> => new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.open("GET", `${API_URL}/trip/video/${video.id}/download`);
            xhr.responseType = "blob";
            xhr.withCredentials = true; // send cookies

            abort.signal.addEventListener("abort", () => {
                xhr.abort();
                reject(new DOMException("Aborted", "AbortError"));
            });

            xhr.onprogress = (e) => {
                if (e.lengthComputable) {
                    setVideoDownloadProgress(Math.round((e.loaded / e.total) * 100));
                } else {
                    setVideoDownloadProgress(Math.min(95, Math.round(e.loaded / 1024 / 1024)));
                }
            };

            xhr.onload = () => {
                if (xhr.status >= 200 && xhr.status < 300) {
                    const blobUrl = URL.createObjectURL(xhr.response);
                    setVideoStreamUrl(blobUrl);
                    setVideoDownloadProgress(100);
                    resolve();
                } else if (xhr.status === 401 && retry) {
                    // Token expired — refresh and retry once
                    doRefresh().then((ok) => {
                        if (!ok || abort.signal.aborted) {
                            reject(new Error("Auth refresh failed"));
                            return;
                        }
                        setVideoDownloadProgress(0);
                        doXhr(false).then(resolve, reject);
                    }).catch(reject);
                } else {
                    reject(new Error(`Failed to fetch video: ${xhr.status}`));
                }
            };

            xhr.onerror = () => reject(new Error("Network error downloading video"));
            xhr.send();
        });

        try {
            await doXhr(true);
        } catch (err: any) {
            if (err?.name === "AbortError") return;
            console.error(err);
            toast.error("Failed to load video preview.");
            setVideoPreviewId(null);
        } finally {
            setIsVideoLoading(false);
        }
    };

    const handleVideoDownload = async (video: Video) => {
        try {
            toast.info(`Starting download: ${video.title}`, { autoClose: 2000 });
            
            // Use authFetch to get the video with proper authentication
            const res = await authFetch(`${API_URL}/trip/video/${video.id}/download`);
            if (!res.ok) throw new Error(`Failed to download video: ${res.status}`);
            
            const blob = await res.blob();
            const url = URL.createObjectURL(blob);
            const artistName = video.artist || selectedArtist?.artist || selectedArtist?.name || "Unknown Artist";
            const filename = `${sanitizeFilename(artistName)} - ${sanitizeFilename(video.title || video.name || "video")}.mp4`;

            const link = document.createElement("a");
            link.href = url;
            link.download = filename;
            document.body.appendChild(link);
            link.click();
            link.remove();
            URL.revokeObjectURL(url);
            
            toast.success(`Downloaded: ${video.title}`, { autoClose: 2000 });
        } catch (error) {
            console.error(error);
            toast.error("Failed to download video.");
        }
    };

    // Submit selected videos via bulk_fetch endpoint (creates a job)
    const handleSubmitVideoRequest = async () => {
        if (selectedVideos.size === 0) {
            toast.error("Please select at least one video.");
            return;
        }

        setIsSubmitting(true);
        try {
            const videoIds = Array.from(selectedVideos).map((id) => 
                typeof id === "string" ? parseInt(id, 10) : id
            );
            const target = selectedArtist?.artist || selectedArtist?.name || videoSearchQuery || "Videos";

            const response = await authFetch(`${API_URL}/trip/videos/bulk_fetch`, {
                method: "POST",
                headers: {
                    "Content-Type": "application/json; charset=utf-8",
                },
                body: JSON.stringify({
                    video_ids: videoIds,
                    target: target,
                }),
            });

            if (!response.ok) {
                throw new Error(`Server error: ${response.status}`);
            }

            const data = await response.json();
            const toastId = 'trip-video-request-submitted';
            toast.success(`Video request submitted! (${videoIds.length} video${videoIds.length !== 1 ? 's' : ''})`, {
                toastId,
                autoClose: 3000,
                onClose: () => {
                    if (typeof window !== 'undefined') window.location.href = '/TRip/requests';
                }
            });
            setSelectedVideos(new Set());
        } catch (err) {
            console.error(err);
            toast.error("Failed to submit video request.");
        } finally {
            setIsSubmitting(false);
        }
    };

    const formatVideoDuration = (duration: number | string | undefined) => {
        if (!duration) return "";
        const secs = typeof duration === "string" ? parseInt(duration, 10) : duration;
        if (!Number.isFinite(secs) || secs <= 0) return "";
        const mins = Math.floor(secs / 60);
        const remainingSecs = Math.floor(secs % 60).toString().padStart(2, "0");
        return `${mins}:${remainingSecs}`;
    };

    useEffect(() => {
        if (typeof Audio === "undefined") {
            return undefined;
        }

        const audio = new Audio();
        audio.preload = "auto";
        audioRef.current = audio;

        const handleEnded = async () => {
            const queue = playbackQueueRef.current;
            const index = queueIndexRef.current;

            if (Array.isArray(queue) && queue.length > 0 && index !== null && index + 1 < queue.length) {
                const nextIndex = index + 1;
                setQueueIndex(nextIndex);
                queueIndexRef.current = nextIndex;
                setAlbumPlaybackLoadingId(queueAlbumIdRef.current);
                try {
                    await playTrack(queue[nextIndex], { fromQueue: true });
                    setAlbumPlaybackLoadingId(null);
                    const upcoming = queue[nextIndex + 1];
                    if (upcoming) prefetchTrack(upcoming);
                } catch (error) {
                    console.error("Failed to advance queue", error);
                    setAlbumPlaybackLoadingId(null);
                    resetQueueState();
                }
                return;
            }

            setIsAudioPlaying(false);
            setCurrentTrackId(null);
            resetQueueState();
        };

        const updateProgress = () => {
            setAudioProgress({ current: audio.currentTime || 0, duration: audio.duration || 0 });
        };

        const handlePause = () => {
            setIsAudioPlaying(false);
            updateProgress();
        };

        const handlePlay = () => {
            setIsAudioPlaying(true);
            updateProgress();
        };

        const handleTimeUpdate = () => {
            updateProgress();
            const queue = playbackQueueRef.current;
            const index = queueIndexRef.current;
            if (!Array.isArray(queue) || queue.length === 0 || index === null) return;
            const nextTrack = queue[index + 1];
            if (!nextTrack) return;

            const duration = audio.duration || 0;
            const currentTime = audio.currentTime || 0;
            const progress = duration > 0 ? currentTime / duration : 0;
            if ((duration > 0 && progress >= 0.7) || (duration === 0 && currentTime >= 15)) {
                prefetchTrack(nextTrack);
            }
        };

        audio.addEventListener("ended", handleEnded);
        audio.addEventListener("pause", handlePause);
        audio.addEventListener("play", handlePlay);
        audio.addEventListener("timeupdate", handleTimeUpdate);
        audio.addEventListener("loadedmetadata", updateProgress);
        audio.addEventListener("seeking", updateProgress);
        audio.addEventListener("seeked", updateProgress);

        return () => {
            audio.pause();
            audio.removeAttribute("src");
            audio.load();
            audio.removeEventListener("ended", handleEnded);
            audio.removeEventListener("pause", handlePause);
            audio.removeEventListener("play", handlePlay);
            audio.removeEventListener("timeupdate", handleTimeUpdate);
            audio.removeEventListener("loadedmetadata", updateProgress);
            audio.removeEventListener("seeking", updateProgress);
            audio.removeEventListener("seeked", updateProgress);
            Object.values(audioSourcesRef.current).forEach((url) => URL.revokeObjectURL(url));
            audioSourcesRef.current = {};
            // Abort any in-flight video download and revoke blob URL
            videoAbortRef.current?.abort();
        };
    }, []);


    useEffect(() => {
        playbackQueueRef.current = playbackQueue;
    }, [playbackQueue]);

    useEffect(() => {
        queueIndexRef.current = queueIndex;
    }, [queueIndex]);

    useEffect(() => {
        queueAlbumIdRef.current = queueAlbumId;
    }, [queueAlbumId]);

    useEffect(() => {
        Object.values(audioSourcesRef.current).forEach((url) => URL.revokeObjectURL(url));
        audioSourcesRef.current = {};
        pendingTrackFetchesRef.current = {};
        if (audioRef.current) {
            audioRef.current.pause();
            audioRef.current.removeAttribute("src");
            audioRef.current.load();
        }
        setIsAudioPlaying(false);
        setAudioLoadingTrackId(null);
        setCurrentTrackId(null);
        resetQueueState();
    }, [quality]);

    const allTracksLoaded = albums.every(({ id }) => Array.isArray(tracksByAlbum[id]) && tracksByAlbum[id].length > 0);

    const handleToggleAllAlbums = () => {
        const allSelected = albums.every(({ id }) => {
            const allTracks = tracksByAlbum[id] || [];
            return selectedTracks[id]?.length === allTracks.length && allTracks.length > 0;
        });

        const newSelection = {};
        albums.forEach(({ id }) => {
            const allTracks = tracksByAlbum[id] || [];
            if (allSelected) {
                // Uncheck all
                newSelection[id] = [];
            } else {
                // Check all tracks in the album
                newSelection[id] = allTracks.map(track => String(track.id));
            }
        });
        setSelectedTracks(newSelection);
    };

    <a
        href="#"
        role="button"
        onClick={(e) => {
            e.preventDefault();
            if (!allTracksLoaded) return; // prevent clicking before data ready
            handleToggleAllAlbums();
        }}
        className={`text-sm hover:underline cursor-pointer ${!allTracksLoaded ? "text-gray-400 dark:text-gray-500 pointer-events-none" : "text-blue-600"
            }`}
    >
        Check / Uncheck All Albums
    </a>



    // Sequentially fetch tracks for albums not loaded yet
    useEffect(() => {
        if (type !== "artist" || albums.length === 0) return;

        let isCancelled = false;
        const albumsToFetch = albums.filter((a) => !tracksByAlbum[a.id]);
        if (albumsToFetch.length === 0) return;

        const fetchTracksSequentially: FetchTracksSequentiallyFn = async () => {
            const minDelay = 650; // ms between API requests
            const maxRetries = 3; // retry up to 3 times on failure
            setIsFetching(true);

            const totalAlbums = albumsToFetch.length;

            for (let index = 0; index < totalAlbums; index++) {
                const album = albumsToFetch[index];

                if (isCancelled) break;

                setLoadingAlbumId(album.id);

                let succeeded = false;
                for (let attempt = 0; attempt < maxRetries && !isCancelled; attempt++) {
                    try {
                        const now = Date.now();
                        if (!fetchTracksSequentially.lastCall) fetchTracksSequentially.lastCall = 0;
                        const elapsed = now - fetchTracksSequentially.lastCall;
                        const currentDelay = attempt === 0 ? minDelay : minDelay + attempt * 1000;
                        if (elapsed < currentDelay) await delay(currentDelay - elapsed);
                        fetchTracksSequentially.lastCall = Date.now();

                        const res = await authFetch(`${API_URL}/trip/get_tracks_by_album_id/${album.id}`);
                        if (!res.ok) throw new Error("API error");
                        const data = await res.json();

                        if (isCancelled) break;

                        setTracksByAlbum((prev) => ({ ...prev, [album.id]: data }));
                        setSelectedTracks((prev) => ({
                            ...prev,
                            [album.id]: data.map((t) => String(t.id)),
                        }));
                        succeeded = true;
                        break; // success — move to next album
                    } catch (err) {
                        if (attempt < maxRetries - 1) {
                            console.warn(`Retry ${attempt + 1}/${maxRetries} for album "${album.album}" (id ${album.id})`);
                        } else {
                            toast.error(`Failed to fetch tracks for album ${album.album}.`);
                            setTracksByAlbum((prev) => ({ ...prev, [album.id]: [] }));
                            setSelectedTracks((prev) => ({ ...prev, [album.id]: [] }));
                        }
                    }
                }

                // Update progress toast
                if (metadataFetchToastId.current !== null) {
                    toast.update(metadataFetchToastId.current, {
                        progress: (index + 1) / totalAlbums,
                        render: `Retrieving metadata... (${index + 1} / ${totalAlbums})`,
                    });
                }
            }

            setLoadingAlbumId(null);
            setIsFetching(false);

            // Finish the toast
            if (metadataFetchToastId.current !== null) {
                toast.update(metadataFetchToastId.current, {
                    render: "Metadata retrieved!",
                    type: "success",
                    progress: 1,
                    autoClose: 1500,
                });
            }
        };

        fetchTracksSequentially();

        return () => {
            isCancelled = true;
        };
    }, [albums, type]);



    // Toggle individual track checkbox
    const toggleTrack = (albumId: string | number, trackId: string | number) => {
        setSelectedTracks((prev) => {
            const current = new Set(prev[albumId] || []);
            if (current.has(String(trackId))) current.delete(String(trackId));
            else current.add(String(trackId));
            return { ...prev, [albumId]: Array.from(current) };
        });
    };

    // Toggle album checkbox (select/deselect all tracks in album)
    const toggleAlbum = (albumId: string | number) => {
        const allTracks = tracksByAlbum[albumId]?.map((t) => String(t.id)) || [];
        setSelectedTracks((prev) => {
            const current = prev[albumId] || [];
            const allSelected = current?.length === allTracks.length;
            return {
                ...prev,
                [albumId]: allSelected ? [] : [...allTracks],
            };
        });
    };

    

    // Submit request handler with progress indicator
    const handleSubmitRequest = async () => {
        if (isFetching) {
            // tracks are not done being fetched
            return toast.error("Still fetching track metadata, please wait a moment.");
        }
        setIsSubmitting(true);
        try {
            const allSelectedIds = Object.values(selectedTracks)
                .filter(arr => Array.isArray(arr)) // skip null entries
                .flat();

            const response = await authFetch(`${API_URL}/trip/bulk_fetch`, {
                method: "POST",
                headers: {
                    "Content-Type": "application/json; charset=utf-8",
                },
                body: JSON.stringify({
                    track_ids: allSelectedIds,
                    target: selectedArtist?.artist || selectedArtist?.name || "",
                    quality: quality,
                }),
            });

            if (!response.ok) {
                throw new Error(`Server error: ${response.status}`);
            }

            const data = await response.json();
            const toastId = 'trip-request-submitted';
            toast.success(`Request submitted! (${allSelectedIds.length} tracks)`, {
                toastId,
                autoClose: 3000,
                onClose: () => {
                    if (typeof window !== 'undefined') window.location.href = '/TRip/requests';
                }
            });
        } catch (err) {
            console.error(err);
            toast.error("Failed to submit request.");
        } finally {
            setIsSubmitting(false);
        }
    };


    return (
        <div className="trip-request-form mx-auto my-10 p-6 rounded-xl shadow-md bg-white dark:bg-neutral-900 text-neutral-900 dark:text-neutral-100 border border-neutral-200 dark:border-neutral-700">
            <style>{`
                        /* Accordion tab backgrounds & text */
                        .p-accordion-tab {
                            background-color: #ffffff;
                            color: #000000;
                        }
                        [data-theme="dark"] .p-accordion-tab {
                            background-color: #1e1e1e;
                            color: #ffffff;
                        }

                        /* Accordion header link */
                        .p-accordion-header .p-accordion-header-link {
                            background-color: #f9f9f9;
                            color: #000000;
                        }
                        [data-theme="dark"] .p-accordion-header .p-accordion-header-link {
                            background-color: #1e1e1e !important;
                            color: #ffffff !important;
                        }

                        /* Accordion content panel */
                        .p-accordion-content {
                            background-color: #fafafa;
                            color: #000000;
                        }
                        [data-theme="dark"] .p-accordion-content {
                            background-color: #2a2a2a;
                            color: #ffffff;
                        }

                        /* Track list UL/LI styling */
                        .p-accordion-content ul {
                            padding-left: 0;
                            margin: 0;
                            list-style: none;
                        }
                        [data-theme="dark"] .p-accordion-content ul {
                            color: #ffffff;
                        }

                        /* Track items */
                        .p-accordion-content li {
                            background-color: #fff;
                            border-bottom: 1px solid #e5e5e5;
                        }
                        [data-theme="dark"] .p-accordion-content li {
                            background-color: #2a2a2a;
                            border-bottom: 1px solid #444;
                        }

                        /* Checkboxes inside track list */
                        .p-accordion-content input[type="checkbox"] {
                            accent-color: #1d4ed8; /* optional for consistent dark mode styling */
                        }

                        /* Loading spinner (optional darker style) */
                        [data-theme="dark"] .animate-spin {
                            border-color: #555;
                            border-top-color: #1d4ed8;
                        }

                        /* Small text like audio quality, duration, version */
                        .p-accordion-content span {
                            color: #555;
                        }
                        [data-theme="dark"] .p-accordion-content span {
                            color: #aaa;
                        }
        `}</style>
            <BreadcrumbNav currentPage="request" />

            {/* Disk Space Indicator - always visible */}
            {diskSpace && diskSpace.usedPercent !== undefined && (
                <div className="mb-4 flex items-center gap-2 text-xs text-neutral-500 dark:text-neutral-400">
                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 7v10c0 2 1 3 3 3h10c2 0 3-1 3-3V7c0-2-1-3-3-3H7c-2 0-3 1-3 3z" />
                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V5c0-1 .5-2 2-2h4c1.5 0 2 1 2 2v2" />
                    </svg>
                    <span>
                        <span className={`font-medium ${diskSpace.usedPercent > 90 ? 'text-red-500' :
                                diskSpace.usedPercent > 75 ? 'text-yellow-500' : 'text-green-600 dark:text-green-400'
                            }`}>{diskSpace.availableFormatted}</span> available
                    </span>
                    <div className="w-20 h-1.5 bg-neutral-200 dark:bg-neutral-700 rounded-full overflow-hidden">
                        <div
                            className={`h-full rounded-full ${diskSpace.usedPercent > 90 ? 'bg-red-500' :
                                diskSpace.usedPercent > 75 ? 'bg-yellow-500' : 'bg-green-500'
                                }`}
                            style={{ width: `${diskSpace.usedPercent}%` }}
                        />
                    </div>
                    <span className="text-neutral-400">({diskSpace.usedPercent}% used)</span>
                </div>
            )}

            <h2 className="text-2xl sm:text-3xl font-bold tracking-tight mb-2">New Request</h2>
            <p className="text-neutral-500 dark:text-neutral-400 text-sm mb-6">Search for an artist to browse and select tracks for download.</p>
            <div className="flex flex-col gap-6">
                <div className="flex flex-col gap-4">
                    <label htmlFor="artistInput">Artist: </label>
                    <AutoComplete
                        id="artistInput"
                        ref={autoCompleteRef}
                        value={selectedArtist || artistInput}
                        suggestions={artistSuggestions}
                        field="artist"
                        completeMethod={searchArtists}
                        onChange={handleArtistChange}
                        minLength={3}
                        placeholder="Artist"
                        dropdown
                        className="w-full"
                        inputClassName="w-full px-3 py-2 rounded border border-neutral-300 dark:border-neutral-600 text-black dark:text-white dark:bg-neutral-800"
                        onShow={attachScrollFix}
                        onHide={cleanupScrollFix}
                        itemTemplate={artistItemTemplate}
                    />

                    {(type === "album" || type === "track") && (
                        <input
                            type="text"
                            className="w-full dark:bg-neutral-800 dark:text-white border border-neutral-300 dark:border-neutral-600 rounded px-3 py-2"
                            value={type === "album" ? albumInput : trackInput}
                            onChange={(e) =>
                                type === "album" ? setAlbumInput(e.target.value) : setTrackInput(e.target.value)
                            }
                            placeholder={type === "album" ? "Album" : "Track"}
                        />
                    )}
                    <div className="flex items-center gap-4 justify-end mt-2">
                        <label htmlFor="qualitySelect" className="text-sm font-medium">
                            Quality:
                        </label>
                        <select
                            id="qualitySelect"
                            value={quality}
                            onChange={(e) => setQuality(e.target.value)}
                            className="border border-neutral-300 dark:border-neutral-600 rounded px-2 py-1 bg-white dark:bg-neutral-800 text-black dark:text-white"
                        >
                            <option value="FLAC">FLAC</option>
                            <option value="Lossy">Lossy</option>
                        </select>
                    </div>

                    <Button onClick={handleSearch} disabled={isSearching}>
                        {isSearching ? (
                            <span className="flex items-center gap-2">
                                <span className="animate-spin h-4 w-4 border-2 border-t-2 border-gray-200 border-t-primary rounded-full"></span>
                                Searching...
                            </span>
                        ) : (
                            "Search"
                        )}
                    </Button>
                </div>

                {type === "artist" && albums.length > 0 && (
                    <>
                        <div className="flex flex-col gap-2 mb-2 sm:flex-row sm:items-center sm:justify-between">
                            <div className="text-sm text-neutral-600 dark:text-neutral-400 text-center sm:text-left">
                                <strong className="mr-2">Albums:</strong> {totalAlbums}
                                <span className="mx-3 sm:inline">|</span>
                                <strong className="mr-2">Tracks:</strong> {totalTracks}
                            </div>
                            <a
                                href="#"
                                role="button"
                                onClick={(e) => {
                                    e.preventDefault();
                                    handleToggleAllAlbums();
                                }}
                                className="text-sm text-blue-600 hover:underline cursor-pointer text-center sm:text-right"
                            >
                                Check / Uncheck All Albums
                            </a>
                        </div>
                        <Accordion
                            multiple
                            className="mt-4"
                            activeIndex={expandedAlbums}
                            onTabChange={(e) => setExpandedAlbums(Array.isArray(e.index) ? e.index : [e.index])}
                        >
                            {albums.map(({ album, id, release_date }, albumIndex) => {
                                const allTracks = tracksByAlbum[id] || [];
                                const selected = selectedTracks[id];

                                // Album checkbox is checked if tracks not loaded (selected === null)
                                // or all tracks loaded and all selected
                                const allChecked =
                                    selected === null || (selected?.length === allTracks.length && allTracks.length > 0);
                                const someChecked =
                                    selected !== null && selected.length > 0 && selected.length < allTracks.length;

                                return (
                                    <AccordionTab
                                        key={id}
                                        header={
                                            <div className="flex flex-wrap items-center gap-3 w-full text-sm">
                                                <input
                                                    type="checkbox"
                                                    checked={allChecked}
                                                    ref={(el) => {
                                                        if (el) el.indeterminate = someChecked;
                                                    }}
                                                    onChange={() => toggleAlbum(id)}
                                                    onClick={(e) => e.stopPropagation()}
                                                    className="trip-checkbox cursor-pointer"
                                                    aria-label={`Select all tracks for album ${album}`}
                                                />
                                                <div className="flex items-center gap-1" onClick={(e) => e.stopPropagation()}>
                                                    <button
                                                        type="button"
                                                        onClick={(e) => {
                                                            e.preventDefault();
                                                            e.stopPropagation();
                                                            handleAlbumPlayPause(id, albumIndex);
                                                        }}
                                                        className={`w-7 h-7 flex items-center justify-center rounded-full border transition-colors disabled:opacity-60 disabled:cursor-not-allowed ${queueAlbumId === id && isAudioPlaying
                                                            ? "border-green-500 text-green-500"
                                                            : "border-neutral-400 text-neutral-600 hover:text-blue-600 hover:border-blue-600"}`}
                                                        aria-label={`${queueAlbumId === id && isAudioPlaying ? "Pause" : "Play"} album ${album}`}
                                                        aria-pressed={queueAlbumId === id && isAudioPlaying}
                                                        disabled={albumPlaybackLoadingId === id}
                                                    >
                                                        {albumPlaybackLoadingId === id ? (
                                                            <InlineSpinner sizeClass="h-3 w-3" />
                                                        ) : queueAlbumId === id && isAudioPlaying ? (
                                                            <PauseIcon />
                                                        ) : (
                                                            <PlayIcon />
                                                        )}
                                                    </button>
                                                    <button
                                                        type="button"
                                                        onClick={(e) => {
                                                            e.preventDefault();
                                                            e.stopPropagation();
                                                            toggleAlbumShuffle(id);
                                                        }}
                                                        className={`w-7 h-7 flex items-center justify-center rounded-full border transition-colors ${shuffleAlbums[id]
                                                            ? "border-blue-600 text-blue-600"
                                                            : "border-neutral-400 text-neutral-500 hover:text-blue-600 hover:border-blue-600"}`}
                                                        aria-label={`Toggle shuffle for album ${album}`}
                                                        aria-pressed={!!shuffleAlbums[id]}
                                                    >
                                                        <ShuffleIcon active={!!shuffleAlbums[id]} />
                                                    </button>
                                                </div>
                                                <span className="flex items-center" title={album || ''}>
                                                    {truncate(album || '', 32)}
                                                    {loadingAlbumId === id && <Spinner />}
                                                </span>
                                                <small className="ml-2 text-neutral-500 dark:text-neutral-400">({release_date || 'Unknown'})</small>
                                                <span className="ml-0 w-full text-xs text-neutral-500 sm:ml-auto sm:w-auto">
                                                    {typeof tracksByAlbum[id] === 'undefined' ? (
                                                        loadingAlbumId === id ? 'Loading...' : '...'
                                                    ) : (
                                                        `${allTracks.length} track${allTracks.length !== 1 ? 's' : ''}`
                                                    )}
                                                </span>
                                            </div>
                                        }

                                    >
                                        {allTracks.length > 0 ? (
                                            <ul className="text-sm">
                                                {allTracks.map((track) => {
                                                    const isCurrentTrack = currentTrackId === track.id;
                                                    const showProgress = isCurrentTrack && audioProgress.duration > 0;
                                                    const safeProgress = {
                                                        current: Math.min(audioProgress.current, audioProgress.duration || 0),
                                                        duration: audioProgress.duration || 0,
                                                    };

                                                    return (
                                                        <li key={track.id} className="py-2">
                                                            <div className="flex flex-wrap items-center gap-3">
                                                                <div className="flex items-center gap-3">
                                                                    <input
                                                                        type="checkbox"
                                                                        checked={selected?.includes(String(track.id))}
                                                                        onChange={() => toggleTrack(id, track.id)}
                                                                        className="trip-checkbox cursor-pointer"
                                                                        aria-label={`Select track ${track.title} `}
                                                                    />
                                                                    <button
                                                                        type="button"
                                                                        onClick={(e) => {
                                                                            e.preventDefault();
                                                                            e.stopPropagation();
                                                                            handleTrackPlayPause(track, id, albumIndex);
                                                                        }}
                                                                        style={{ touchAction: "manipulation", WebkitTapHighlightColor: "transparent" }}
                                                                        className={`flex items-center justify-center w-8 h-8 rounded-full border text-sm transition-colors disabled:opacity-60 disabled:cursor-not-allowed select-none ${isCurrentTrack && isAudioPlaying
                                                                            ? "border-green-600 text-green-600"
                                                                            : "border-neutral-400 text-neutral-600 hover:text-blue-600 hover:border-blue-600"}`}
                                                                        aria-label={`${isCurrentTrack && isAudioPlaying ? "Pause" : "Play"} ${track.title}`}
                                                                        aria-pressed={isCurrentTrack && isAudioPlaying}
                                                                        disabled={audioLoadingTrackId === track.id || playPauseClickRef.current}
                                                                    >
                                                                        {audioLoadingTrackId === track.id ? (
                                                                            <InlineSpinner sizeClass="h-4 w-4" />
                                                                        ) : isCurrentTrack && isAudioPlaying ? (
                                                                            <PauseIcon />
                                                                        ) : (
                                                                            <PlayIcon />
                                                                        )}
                                                                    </button>
                                                                </div>
                                                                <div className="flex-1 min-w-0 text-left">
                                                                    <span className="block truncate" title={track.title}>
                                                                        {truncate(track.title, 80)}
                                                                    </span>
                                                                    {track.version && (
                                                                        <span className="block text-[0.7rem] text-neutral-500 truncate" title={track.version}>
                                                                            {track.version}
                                                                        </span>
                                                                    )}
                                                                </div>
                                                                <div className="flex items-center gap-3 text-xs text-neutral-500 w-full justify-between sm:w-auto sm:justify-end">
                                                                    <button
                                                                        type="button"
                                                                        onClick={() => handleTrackDownload(track)}
                                                                        className="text-neutral-500 hover:text-blue-600 underline whitespace-nowrap cursor-pointer"
                                                                        aria-label={`Download ${track.title}`}
                                                                    >
                                                                        Download
                                                                    </button>
                                                                    <span>{quality}</span>
                                                                    {track.duration && (
                                                                        <span className="tabular-nums">{track.duration}</span>
                                                                    )}
                                                                </div>
                                                            </div>
                                                            {showProgress && (
                                                                <div className="mt-2 pr-2 pl-4 sm:pr-6 sm:pl-16">
                                                                    <input
                                                                        type="range"
                                                                        min="0"
                                                                        max={safeProgress.duration}
                                                                        value={safeProgress.current}
                                                                        step="0.25"
                                                                        onChange={(e) => {
                                                                            if (!audioRef.current) return;
                                                                            const nextValue = Number(e.target.value);
                                                                            audioRef.current.currentTime = nextValue;
                                                                            setAudioProgress((prev) => ({ ...prev, current: nextValue }));
                                                                        }}
                                                                        className="w-full h-1 cursor-pointer accent-blue-600"
                                                                        aria-label={`Seek within ${track.title}`}
                                                                    />
                                                                    <div className="flex justify-between text-[0.65rem] text-neutral-500 mt-1">
                                                                        <span>{formatTime(safeProgress.current)}</span>
                                                                        <span>{formatTime(safeProgress.duration)}</span>
                                                                    </div>
                                                                </div>
                                                            )}
                                                        </li>
                                                    );
                                                })}
                                            </ul>
                                        ) : (
                                            <div className="text-sm italic text-neutral-600 dark:text-neutral-400">
                                                {tracksByAlbum[id] ? "No tracks found for this album." : "Loading tracks..."}
                                            </div>
                                        )}
                                    </AccordionTab>
                                );
                            })}
                        </Accordion>
                        <div className="flex justify-end mt-4">
                            <Button onClick={handleSubmitRequest} color="primary" disabled={isSubmitting}>
                                {isSubmitting ? (
                                    <span className="flex items-center gap-2">
                                        <span className="animate-spin h-4 w-4 border-2 border-t-2 border-gray-200 border-t-primary rounded-full"></span>
                                        Submitting...
                                    </span>
                                ) : (
                                    "Submit Request"
                                )}
                            </Button>
                        </div>

                        {/* Videos Section - Show when artist is selected or videos are loaded */}
                        {(selectedArtist || (showVideoSection && videoResults.length > 0)) && (
                            <div className="mt-8 pt-6 border-t border-neutral-200 dark:border-neutral-700">
                                <div className="flex items-center justify-between mb-4">
                                    <h3 className="text-lg font-semibold flex items-center gap-2">
                                        <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" />
                                        </svg>
                                        Music Videos
                                    </h3>
                                    <button
                                        type="button"
                                        className={`px-3 py-1.5 text-sm font-medium rounded-md border transition-colors
                                            ${showVideoSection
                                                ? 'bg-blue-600 text-white border-blue-600 hover:bg-blue-700'
                                                : 'border-neutral-400 dark:border-neutral-600 text-neutral-700 dark:text-neutral-300 hover:bg-neutral-100 dark:hover:bg-neutral-800'
                                            }
                                            disabled:opacity-50 disabled:cursor-not-allowed`}
                                        onClick={() => {
                                            if (!showVideoSection && selectedArtist) {
                                                fetchArtistVideos(selectedArtist.id);
                                            } else {
                                                setShowVideoSection(!showVideoSection);
                                            }
                                        }}
                                        disabled={isVideoSearching}
                                    >
                                        {isVideoSearching ? (
                                            <span className="flex items-center gap-2">
                                                <InlineSpinner sizeClass="h-3 w-3" />
                                                Loading...
                                            </span>
                                        ) : showVideoSection ? (
                                            "Hide Videos"
                                        ) : (
                                            "Browse Videos"
                                        )}
                                    </button>
                                </div>

                                {showVideoSection && (
                                    <div className="space-y-4">
                                        {/* Video Search Bar */}
                                        <div className="flex gap-2">
                                            <input
                                                type="text"
                                                value={videoSearchQuery}
                                                onChange={(e) => setVideoSearchQuery(e.target.value)}
                                                onKeyDown={(e) => e.key === "Enter" && searchVideos()}
                                                placeholder="Search videos by title..."
                                                className="flex-1 px-3 py-2 rounded border border-neutral-300 dark:border-neutral-600 bg-white dark:bg-neutral-800 text-black dark:text-white"
                                            />
                                            <button
                                                type="button"
                                                onClick={searchVideos}
                                                disabled={isVideoSearching}
                                                className="px-4 py-2 text-sm font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                                            >
                                                {isVideoSearching ? <InlineSpinner sizeClass="h-4 w-4" /> : "Search"}
                                            </button>
                                        </div>

                                        {/* Video Select All / Count */}
                                        {videoResults.length > 0 && (
                                            <div className="flex items-center justify-between">
                                                <span className="text-sm text-neutral-600 dark:text-neutral-400">
                                                    <strong>{videoResults.length}</strong> video{videoResults.length !== 1 ? 's' : ''} found
                                                </span>
                                                <a
                                                    href="#"
                                                    role="button"
                                                    onClick={(e) => {
                                                        e.preventDefault();
                                                        if (selectedVideos.size === videoResults.length) {
                                                            setSelectedVideos(new Set());
                                                        } else {
                                                            setSelectedVideos(new Set(videoResults.map((v) => v.id)));
                                                        }
                                                    }}
                                                    className="text-sm text-blue-600 hover:underline cursor-pointer"
                                                >
                                                    {selectedVideos.size === videoResults.length ? 'Uncheck All' : 'Check All'}
                                                </a>
                                            </div>
                                        )}

                                        {/* Video Results Grid */}
                                        {videoResults.length > 0 ? (
                                            <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
                                                {videoResults.map((video) => (
                                                    <div
                                                        key={video.id}
                                                        className={`relative rounded-lg border overflow-hidden transition-all ${
                                                            selectedVideos.has(video.id)
                                                                ? "border-blue-500 ring-2 ring-blue-500/30"
                                                                : "border-neutral-200 dark:border-neutral-700"
                                                        }`}
                                                    >
                                                        {/* Video Thumbnail / Player area */}
                                                        {videoPreviewId === video.id && videoStreamUrl ? (
                                                            /* Active video player — blob URL has correct duration & seeking */
                                                            <div className="relative aspect-video bg-black">
                                                                <video
                                                                    src={videoStreamUrl}
                                                                    controls
                                                                    autoPlay
                                                                    className="w-full h-full"
                                                                    onError={() => {
                                                                        toast.error("Failed to play video");
                                                                        if (videoStreamUrl?.startsWith("blob:")) URL.revokeObjectURL(videoStreamUrl);
                                                                        setVideoPreviewId(null);
                                                                        setVideoStreamUrl(null);
                                                                    }}
                                                                />
                                                            </div>
                                                        ) : (
                                                            /* Thumbnail with play/progress overlay */
                                                            <div
                                                                className="relative aspect-video bg-neutral-200 dark:bg-neutral-800 cursor-pointer group"
                                                                onClick={() => handleVideoPreview(video)}
                                                            >
                                                                {video.image || video.imageUrl ? (
                                                                    <img
                                                                        src={video.image || video.imageUrl}
                                                                        alt={video.title}
                                                                        className="w-full h-full object-cover"
                                                                    />
                                                                ) : (
                                                                    <div className="w-full h-full flex items-center justify-center text-neutral-400">
                                                                        <svg className="w-12 h-12" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                                            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" />
                                                                        </svg>
                                                                    </div>
                                                                )}
                                                                {/* Play / Download progress overlay */}
                                                                <div className={`absolute inset-0 flex flex-col items-center justify-center transition-opacity ${
                                                                    isVideoLoading && videoPreviewId === video.id
                                                                        ? 'bg-black/60 opacity-100'
                                                                        : 'bg-black/30 opacity-0 group-hover:opacity-100'
                                                                }`}>
                                                                    {isVideoLoading && videoPreviewId === video.id ? (
                                                                        <>
                                                                            <InlineSpinner sizeClass="h-6 w-6" />
                                                                            <span className="text-white text-xs mt-2 font-medium">
                                                                                {videoDownloadProgress > 0
                                                                                    ? `Loading… ${videoDownloadProgress}%`
                                                                                    : 'Connecting…'}
                                                                            </span>
                                                                            {/* Progress bar */}
                                                                            <div className="w-3/4 mt-2 h-1.5 bg-white/20 rounded-full overflow-hidden">
                                                                                <div
                                                                                    className="h-full bg-blue-400 rounded-full transition-all duration-300"
                                                                                    style={{ width: `${videoDownloadProgress}%` }}
                                                                                />
                                                                            </div>
                                                                        </>
                                                                    ) : (
                                                                        <svg className="w-12 h-12 text-white" fill="currentColor" viewBox="0 0 24 24">
                                                                            <path d="M8 5v14l11-7z" />
                                                                        </svg>
                                                                    )}
                                                                </div>
                                                                {/* Duration badge */}
                                                                {video.duration && (
                                                                    <span className="absolute bottom-2 right-2 px-1.5 py-0.5 bg-black/70 text-white text-xs rounded">
                                                                        {formatVideoDuration(video.duration)}
                                                                    </span>
                                                                )}
                                                            </div>
                                                        )}

                                                        {/* Video Info */}
                                                        <div className="p-3">
                                                            <div className="flex items-start gap-2">
                                                                <input
                                                                    type="checkbox"
                                                                    checked={selectedVideos.has(video.id)}
                                                                    onChange={() => toggleVideoSelection(video.id)}
                                                                    className="mt-1 cursor-pointer"
                                                                />
                                                                <div className="flex-1 min-w-0">
                                                                    <p className="font-medium text-sm truncate" title={video.title}>
                                                                        {video.title}
                                                                    </p>
                                                                    {video.artist && (
                                                                        <p className="text-xs text-neutral-500 truncate">
                                                                            {video.artist}
                                                                        </p>
                                                                    )}
                                                                </div>
                                                            </div>
                                                            <div className="flex justify-end mt-2">
                                                                <button
                                                                    onClick={() => handleVideoDownload(video)}
                                                                    className="text-xs text-blue-600 hover:underline"
                                                                >
                                                                    Download
                                                                </button>
                                                            </div>
                                                        </div>
                                                    </div>
                                                ))}
                                            </div>
                                        ) : !isVideoSearching && showVideoSection ? (
                                            <div className="text-center py-8 text-neutral-500">
                                                <svg className="w-12 h-12 mx-auto mb-2 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" />
                                                </svg>
                                                <p>No videos found. Try searching for something else.</p>
                                            </div>
                                        ) : null}

                                        {/* Selected Videos Summary */}
                                        {selectedVideos.size > 0 && (
                                            <div className="flex items-center justify-between p-3 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800">
                                                <span className="text-sm text-neutral-800 dark:text-neutral-200">
                                                    <strong>{selectedVideos.size}</strong> video{selectedVideos.size !== 1 ? "s" : ""} selected
                                                </span>
                                                <button
                                                    type="button"
                                                    onClick={handleSubmitVideoRequest}
                                                    disabled={isSubmitting}
                                                    className="px-4 py-1.5 text-sm font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
                                                >
                                                    {isSubmitting ? (
                                                        <span className="flex items-center gap-2">
                                                            <InlineSpinner sizeClass="h-3 w-3" />
                                                            Submitting...
                                                        </span>
                                                    ) : (
                                                        "Submit Video Request"
                                                    )}
                                                </button>
                                            </div>
                                        )}
                                    </div>
                                )}
                            </div>
                        )}
                    </>
                )
                }
            </div >
        </div >
    );
}
