import {
    Archive,
    ArrowDownWideNarrow,
    Check,
    ChevronDown,
    FileAudio,
    FileImage,
    FileSpreadsheet,
    FileText,
    FileType,
    FileVideo,
    FolderOpen,
    Image as ImageIcon,
    ListPlus,
    LoaderCircle,
    Search,
    SearchX,
    SquareCheckBig,
    Upload,
    X,
    CheckCircle2,
    AlertCircle,
    ImagePlus,
    Download,
    Trash2,
} from 'lucide-react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { toast } from 'sonner';
import {
    AlertDialog,
    AlertDialogAction,
    AlertDialogCancel,
    AlertDialogContent,
    AlertDialogDescription,
    AlertDialogFooter,
    AlertDialogHeader,
    AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { Button } from '@/components/ui/button';
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogHeader,
    DialogTitle,
} from '@/components/ui/dialog';
import {
    DropdownMenu,
    DropdownMenuCheckboxItem,
    DropdownMenuContent,
    DropdownMenuLabel,
    DropdownMenuSeparator,
    DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Input } from '@/components/ui/input';
import {
    Pagination,
    PaginationContent,
    PaginationEllipsis,
    PaginationItem,
    PaginationLink,
    PaginationNext,
    PaginationPrevious,
} from '@/components/ui/pagination';
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from '@/components/ui/select';
import { compressImage, isCompressibleImage } from '@/lib/compress-image';
import { cn } from '@/lib/utils';
import { picker } from '@/routes/admin/media';

export type MediaPickerItem = {
    id: number;
    name: string;
    collection: string;
    mime: string | null;
    size: number;
    url: string;
    thumb_url: string;
    width: number | null;
    height: number | null;
    alt: { id: string; en: string };
    created_at?: string;
    usage?: {
        in_use: boolean;
        attached: string[];
        referenced: string[];
    };
};

type Props = {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    /**
     * Dipanggil saat pilihan final. Mode tunggal: satu item. Mode multi:
     * array item terpilih (urutan sesuai klik) — kosong bila dibatalkan.
     */
    onSelect: (media: MediaPickerItem | MediaPickerItem[]) => void;
    /** Mode multi-pilih — klik item untuk toggle, footer untuk menyisipkan. */
    multiple?: boolean;
    /** Sembunyikan browser library saat dialog hanya dipakai untuk upload. */
    showLibrary?: boolean;
};

// Kategori tipe file — kunci sama dengan MEDIA_TYPE_EXTENSIONS di backend.
const MEDIA_TYPES = [
    { key: 'image', label: 'Gambar (PNG, JPG, WEBP...)', icon: FileImage },
    { key: 'pdf', label: 'PDF', icon: FileText },
    {
        key: 'spreadsheet',
        label: 'Spreadsheet (XLS, XLSX, CSV)',
        icon: FileSpreadsheet,
    },
    { key: 'word', label: 'Dokumen (DOC, DOCX)', icon: FileText },
    { key: 'text', label: 'Teks (TXT, MD)', icon: FileText },
    { key: 'archive', label: 'Arsip (ZIP, RAR...)', icon: Archive },
    { key: 'video', label: 'Video (MP4, WEBM...)', icon: FileVideo },
    { key: 'audio', label: 'Audio (MP3, WAV...)', icon: FileAudio },
] as const;

type SortValue = 'desc' | 'asc';

type UploadItem = {
    id: string;
    file: File;
    originalSize: number;
    compressedSize: number;
    savings: number;
    previewUrl: string;
    status: 'pending' | 'compressing' | 'uploading' | 'done' | 'error';
    progress?: number;
    error?: string;
    resultUrl?: string;
    resultId?: number;
};

const formatSize = (bytes: number): string => {
    if (!bytes) {
        return '—';
    }

    if (bytes >= 1024 * 1024) {
        return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
    }

    return `${Math.max(1, Math.round(bytes / 1024))} KB`;
};

/** Nomor halaman dengan ellipsis, mis. [1, '…', 4, 5, 6, '…', 12]. */
const pageItems = (current: number, last: number): (number | 'ellipsis')[] => {
    if (last <= 7) {
        return Array.from({ length: last }, (_, i) => i + 1);
    }

    const items = new Set<number>([1, last, current - 1, current, current + 1]);

    const sorted = [...items]
        .filter((n) => n >= 1 && n <= last)
        .sort((a, b) => a - b);
    const out: (number | 'ellipsis')[] = [];

    sorted.forEach((n, i) => {
        if (i > 0 && n - sorted[i - 1] > 1) {
            out.push('ellipsis');
        }

        out.push(n);
    });

    return out;
};

/**
 * Dialog Media Picker — grid thumbnail dari library media + pencarian live +
 * sort (terbaru/terlama) + filter tipe file multi-select + pagination shadcn +
 * ukuran file di tiap kartu + upload file langsung dari dialog.
 */
export function MediaPickerDialog({
    open,
    onOpenChange,
    onSelect,
    multiple = false,
    showLibrary = true,
}: Props) {
    const [items, setItems] = useState<MediaPickerItem[]>([]);
    const [search, setSearch] = useState('');
    const [sort, setSort] = useState<SortValue>('desc');
    const [types, setTypes] = useState<string[]>([]);
    const [collection, setCollection] = useState('');
    const [availableCollections, setAvailableCollections] = useState<string[]>(
        [],
    );
    const [loading, setLoading] = useState(true);
    const [page, setPage] = useState(1);
    const [lastPage, setLastPage] = useState(1);
    const [total, setTotal] = useState(0);
    const [selected, setSelected] = useState<Set<number>>(new Set());
    const [detailItem, setDetailItem] = useState<MediaPickerItem | null>(null);
    const [deletingSelected, setDeletingSelected] = useState(false);
    const [deleteConfirmOpen, setDeleteConfirmOpen] = useState(false);
    const [editingAlt, setEditingAlt] = useState(false);
    const [savingAlt, setSavingAlt] = useState(false);
    const [altDraft, setAltDraft] = useState({ id: '', en: '' });
    const debounceRef = useRef<number | null>(null);
    const requestSeq = useRef(0);

    // Upload state — multi file
    const [uploadQueue, setUploadQueue] = useState<UploadItem[]>([]);
    const [isProcessing, setIsProcessing] = useState(false);
    const fileInputRef = useRef<HTMLInputElement>(null);
    const uploadRequests = useRef(new Map<string, XMLHttpRequest>());
    const cancelledUploads = useRef(new Set<string>());
    const allowClose = useRef(false);

    // Muat daftar koleksi saat dialog dibuka.
    useEffect(() => {
        if (!open) {
return;
}

        const timer = window.setTimeout(async () => {
            try {
                const response = await fetch('/admin/media/collections', {
                    credentials: 'same-origin',
                    headers: {
                        Accept: 'application/json',
                        'X-Requested-With': 'XMLHttpRequest',
                    },
                });

                if (response.ok) {
                    const data = await response.json();
                    setAvailableCollections(data.collections ?? []);
                }
            } catch {
                // ignore
            }
        }, 0);

        return () => window.clearTimeout(timer);
    }, [open]);

    // Reset upload state saat dialog ditutup
    useEffect(() => {
        if (!open) {
            uploadRequests.current.forEach((request) => request.abort());
            uploadRequests.current.clear();
            cancelledUploads.current.clear();
            // Bersihkan object URLs
            uploadQueue.forEach((item) => {
                if (item.previewUrl) {
URL.revokeObjectURL(item.previewUrl);
}
            });
            setUploadQueue([]);
            setIsProcessing(false);
            allowClose.current = false;
        }
    }, [open]);

    const load = useCallback(
        async (
            query: string,
            sortValue: SortValue,
            typeList: string[],
            collectionValue: string,
            pageNum: number,
        ) => {
            const seq = ++requestSeq.current;

            try {
                const url = picker({
                    query: {
                        search: query,
                        sort: sortValue,
                        page: String(pageNum),
                        ...(typeList.length > 0
                            ? { types: typeList.join(',') }
                            : {}),
                        ...(collectionValue
                            ? { collection: collectionValue }
                            : {}),
                    },
                }).url;

                const response = await fetch(url, {
                    headers: {
                        Accept: 'application/json',
                        'X-Requested-With': 'XMLHttpRequest',
                    },
                });

                if (!response.ok) {
                    return;
                }

                const data = await response.json();

                // Abaikan respons basi (urutan request berubah karena filter baru).
                if (seq !== requestSeq.current) {
                    return;
                }

                setItems(data.data);
                setPage(data.current_page);
                setLastPage(data.last_page);
                setTotal(data.total);
            } finally {
                if (seq === requestSeq.current) {
                    setLoading(false);
                }
            }
        },
        [],
    );

    // Muat halaman pertama saat komponen di-mount
    useEffect(() => {
        if (!showLibrary) {
return;
}

        const timer = window.setTimeout(() => load('', 'desc', [], '', 1), 0);

        return () => window.clearTimeout(timer);
    }, [load, showLibrary]);

    // Bersihkan debounce saat komponen di-unmount.
    useEffect(() => {
        return () => {
            if (debounceRef.current) {
                window.clearTimeout(debounceRef.current);
            }
        };
    }, []);

    // Mode multi: reset seleksi saat dialog dibuka ulang
    useEffect(() => {
        if (!(open && multiple)) {
            return;
        }

        const timer = window.setTimeout(() => setSelected(new Set()), 0);

        return () => window.clearTimeout(timer);
    }, [multiple, open]);

    // --- Upload handlers (multi-file) ---

    let uploadIdCounter = 0;
    const nextUploadId = () => `upload-${++uploadIdCounter}-${Date.now()}`;

    const handleFileSelect = async (fileList: FileList | null) => {
        if (!fileList?.length) {
return;
}

        // Salin FileList sebelum input di-reset; pada beberapa browser,
        // mereset input membuat FileList yang diterima ikut menjadi kosong.
        const selectedFiles = Array.from(fileList);

        // Reset input supaya bisa pilih file yang sama lagi
        if (fileInputRef.current) {
            fileInputRef.current.value = '';
        }

        const newItems: UploadItem[] = [];

        for (const file of selectedFiles) {
            const previewUrl = file.type.startsWith('image/')
                ? URL.createObjectURL(file)
                : '';

            newItems.push({
                id: nextUploadId(),
                file,
                originalSize: file.size,
                compressedSize: file.size,
                savings: 0,
                previewUrl,
                status: 'pending',
            });
        }

        setUploadQueue((prev) => [...prev, ...newItems]);

        for (const [index, item] of newItems.entries()) {
            const sourceFile = selectedFiles[index];

            if (!isCompressibleImage(sourceFile)) {
                setUploadQueue((prev) =>
                    prev.map((current) =>
                        current.id === item.id
                            ? { ...current, status: 'compressing', progress: 0 }
                            : current,
                    ),
                );
                window.requestAnimationFrame(() => {
                    setUploadQueue((prev) =>
                        prev.map((current) =>
                            current.id === item.id
                                ? {
                                      ...current,
                                      status: 'pending',
                                      progress: 100,
                                  }
                                : current,
                        ),
                    );
                });
                continue;
            }

            setUploadQueue((prev) =>
                prev.map((current) =>
                    current.id === item.id
                        ? { ...current, status: 'compressing', progress: 0 }
                        : current,
                ),
            );

            try {
                const result = await compressImage(sourceFile, {
                    quality: 0.8,
                    maxDimension: 1920,
                });
                const previewUrl = URL.createObjectURL(result.file);

                setUploadQueue((prev) =>
                    prev.map((current) =>
                        current.id === item.id
                            ? {
                                  ...current,
                                  file: result.file,
                                  compressedSize: result.compressedSize,
                                  savings: result.savings,
                                  previewUrl,
                                  status: 'pending',
                                  progress: 100,
                              }
                            : current,
                    ),
                );
            } catch {
                setUploadQueue((prev) =>
                    prev.map((current) =>
                        current.id === item.id
                            ? { ...current, status: 'pending', progress: 100 }
                            : current,
                    ),
                );
            }
        }
    };

    const removeUploadItem = (itemId: string) => {
        cancelledUploads.current.add(itemId);
        uploadRequests.current.get(itemId)?.abort();
        uploadRequests.current.delete(itemId);
        setUploadQueue((prev) => {
            const item = prev.find((i) => i.id === itemId);

            if (item?.previewUrl) {
URL.revokeObjectURL(item.previewUrl);
}

            return prev.filter((i) => i.id !== itemId);
        });
    };

    const cancelAllUploads = () => {
        uploadQueue.forEach((item) => cancelledUploads.current.add(item.id));
        uploadRequests.current.forEach((request) => request.abort());
        uploadRequests.current.clear();
        uploadQueue.forEach((item) => {
            if (item.previewUrl) {
URL.revokeObjectURL(item.previewUrl);
}
        });
        setUploadQueue([]);
        setIsProcessing(false);
    };

    const uploadFile = (
        item: UploadItem,
        file: File,
    ): Promise<MediaPickerItem> =>
        new Promise((resolve, reject) => {
            const formData = new FormData();
            formData.append('file', file);
            formData.append('collection', 'general');

            const request = new XMLHttpRequest();
            uploadRequests.current.set(item.id, request);
            request.open('POST', '/admin/media/editor-upload');
            request.withCredentials = true;
            request.setRequestHeader('Accept', 'application/json');
            request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
            request.setRequestHeader(
                'X-XSRF-TOKEN',
                decodeURIComponent(
                    document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1] ?? '',
                ),
            );
            request.upload.addEventListener('progress', (event) => {
                if (event.lengthComputable) {
                    const progress = Math.round(
                        (event.loaded / event.total) * 100,
                    );
                    setUploadQueue((prev) =>
                        prev.map((current) =>
                            current.id === item.id
                                ? { ...current, progress }
                                : current,
                        ),
                    );
                }
            });
            request.addEventListener('load', () => {
                uploadRequests.current.delete(item.id);

                if (request.status < 200 || request.status >= 300) {
                    reject(new Error('Upload gagal'));

                    return;
                }

                try {
                    const data = JSON.parse(request.responseText);
                    resolve({
                        id: data.id,
                        name: item.file.name,
                        collection: 'general',
                        mime: item.file.type,
                        size: file.size,
                        url: data.url,
                        thumb_url: data.url,
                        width: null,
                        height: null,
                        alt: { id: '', en: '' },
                    });
                } catch {
                    reject(new Error('Respons upload tidak valid'));
                }
            });
            request.addEventListener('error', () => {
                uploadRequests.current.delete(item.id);
                reject(new Error('Upload gagal'));
            });
            request.addEventListener('abort', () => {
                uploadRequests.current.delete(item.id);
                reject(new Error('Upload dibatalkan'));
            });
            request.send(formData);
        });

    const processUploadQueue = async (itemsToProcess?: UploadItem[]) => {
        setIsProcessing(true);

        const queue = [...(itemsToProcess ?? uploadQueue)].filter(
            (i) => i.status === 'pending',
        );
        const newUploadedItems: MediaPickerItem[] = [];

        for (const item of queue) {
            if (cancelledUploads.current.has(item.id)) {
                continue;
            }

            const fileToUpload = item.file;
            const compressedSize = item.compressedSize;

            // Step 2: Upload
            setUploadQueue((prev) =>
                prev.map((i) =>
                    i.id === item.id
                        ? { ...i, status: 'uploading', progress: 0 }
                        : i,
                ),
            );

            try {
                const uploaded = await uploadFile(item, fileToUpload);

                setUploadQueue((prev) =>
                    prev.map((i) =>
                        i.id === item.id
                            ? {
                                  ...i,
                                  status: 'done',
                                  progress: 100,
                                  resultUrl: uploaded.url,
                                  resultId: uploaded.id,
                              }
                            : i,
                    ),
                );

                newUploadedItems.push({ ...uploaded, size: compressedSize });
            } catch (err) {
                if (cancelledUploads.current.has(item.id)) {
                    continue;
                }

                setUploadQueue((prev) =>
                    prev.map((i) =>
                        i.id === item.id
                            ? {
                                  ...i,
                                  status: 'error',
                                  error:
                                      err instanceof Error
                                          ? err.message
                                          : 'Gagal mengunggah',
                              }
                            : i,
                    ),
                );
            }
        }

        setIsProcessing(false);

        // Muat ulang library
        if (newUploadedItems.length > 0) {
            setLoading(true);
            await load(search, sort, types, collection, 1);

            // Masukkan hasil upload ke pemanggil, termasuk mode multi-select.
            if (newUploadedItems.length > 0) {
                allowClose.current = true;
                onSelect(multiple ? newUploadedItems : newUploadedItems[0]);
                onOpenChange(false);
            }
        }
    };

    const handleDrop = (e: React.DragEvent) => {
        e.preventDefault();
        e.stopPropagation();
        handleFileSelect(e.dataTransfer.files);
    };

    const handleDragOver = (e: React.DragEvent) => {
        e.preventDefault();
        e.stopPropagation();
    };

    const allDone =
        uploadQueue.length > 0 &&
        uploadQueue.every((i) => i.status === 'done' || i.status === 'error');
    const hasPending = uploadQueue.some((i) => i.status === 'pending');
    const doneCount = uploadQueue.filter((i) => i.status === 'done').length;
    const errorCount = uploadQueue.filter((i) => i.status === 'error').length;

    // --- Filter & search handlers ---

    const handleSearchChange = (value: string) => {
        setSearch(value);

        if (debounceRef.current) {
            window.clearTimeout(debounceRef.current);
        }

        debounceRef.current = window.setTimeout(() => {
            setLoading(true);
            load(value, sort, types, collection, 1);
        }, 300);
    };

    const handleSortChange = (value: string) => {
        const next = value === 'asc' ? 'asc' : 'desc';

        setSort(next);
        setLoading(true);
        load(search, next, types, collection, 1);
    };

    const toggleType = (key: string) => {
        const next = types.includes(key)
            ? types.filter((item) => item !== key)
            : [...types, key];

        setTypes(next);
        setLoading(true);
        load(search, sort, next, collection, 1);
    };

    const clearTypes = () => {
        setTypes([]);
        setLoading(true);
        load(search, sort, [], collection, 1);
    };

    const handleCollectionChange = (value: string) => {
        const next = value === 'all' ? '' : value;
        setCollection(next);
        setLoading(true);
        load(search, sort, types, next, 1);
    };

    const goToPage = (nextPage: number) => {
        if (nextPage < 1 || nextPage > lastPage || nextPage === page) {
            return;
        }

        setLoading(true);
        load(search, sort, types, collection, nextPage);
    };

    const toggleSelect = (id: number) => {
        setSelected((current) => {
            const next = new Set(current);

            if (next.has(id)) {
                next.delete(id);
            } else {
                next.add(id);
            }

            return next;
        });
    };

    const handleSelect = (item: MediaPickerItem) => {
        if (multiple) {
            toggleSelect(item.id);

            return;
        }

        onSelect(item);
        onOpenChange(false);
    };

    const handleInsertSelected = () => {
        const chosen = items.filter((item) => selected.has(item.id));

        onSelect(chosen);
        onOpenChange(false);
    };

    const handleClearSelection = () => {
        setSelected(new Set());
    };

    const handleDeleteSelected = async () => {
        if (selected.size === 0) {
return;
}

        setDeletingSelected(true);

        try {
            const response = await fetch('/admin/media/bulk-delete', {
                method: 'POST',
                credentials: 'same-origin',
                headers: {
                    Accept: 'application/json',
                    'Content-Type': 'application/json',
                    'X-Requested-With': 'XMLHttpRequest',
                    'X-XSRF-TOKEN': decodeURIComponent(
                        document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1] ?? '',
                    ),
                },
                body: JSON.stringify({ ids: [...selected] }),
            });

            if (!response.ok) {
                throw new Error('Media gagal dihapus');
            }

            setSelected(new Set());
            setLoading(true);
            await load(search, sort, types, collection, page);
        } finally {
            setDeletingSelected(false);
            setDeleteConfirmOpen(false);
        }
    };

    const openDetail = (item: MediaPickerItem) => {
        setDetailItem(item);
        setAltDraft(item.alt);
        setEditingAlt(false);
    };

    const saveAlt = () => {
        if (!detailItem) {
return;
}

        setSavingAlt(true);

        fetch(`/admin/media/${detailItem.id}`, {
            method: 'PUT',
            credentials: 'same-origin',
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
                'X-Requested-With': 'XMLHttpRequest',
                'X-XSRF-TOKEN': decodeURIComponent(
                    document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1] ?? '',
                ),
            },
            body: JSON.stringify({ alt: altDraft }),
        })
            .then(async (response) => {
                if (!response.ok) {
                    throw new Error('Alt text gagal disimpan.');
                }

                return response.json();
            })
            .then(() => {
                const updated = { ...detailItem, alt: altDraft };
                setDetailItem(updated);
                setItems((current) =>
                    current.map((item) =>
                        item.id === updated.id ? updated : item,
                    ),
                );
                setEditingAlt(false);
                toast.success('Alt text berhasil disimpan.');
            })
            .catch((error: unknown) => {
                toast.error(
                    error instanceof Error
                        ? error.message
                        : 'Alt text gagal disimpan.',
                );
            })
            .finally(() => {
                setSavingAlt(false);
            });
    };

    const selectedLabel =
        types.length === 0
            ? 'Semua Tipe'
            : types.length === 1
              ? `Tipe: ${MEDIA_TYPES.find((t) => t.key === types[0])?.label.split(' ')[0] ?? types[0]}`
              : `Tipe (${types.length})`;

    return (
        <>
            <Dialog
                open={open}
                onOpenChange={(nextOpen) => {
                if (
                    !nextOpen &&
                    uploadQueue.length > 0 &&
                    !allowClose.current
                ) {
                    return;
                }

                onOpenChange(nextOpen);
            }}
        >
            <DialogContent
                className="sm:max-w-6xl"
                onPointerDownOutside={(e) => {
                    e.preventDefault();
                }}
                onInteractOutside={(e) => {
                    e.preventDefault();
                }}
            >
                <DialogHeader>
                    <DialogTitle>Library Media</DialogTitle>
                    <DialogDescription>
                        Pilih media dari library atau unggah file baru.
                    </DialogDescription>
                </DialogHeader>

                {/* Upload Zone — multi-file drag & drop */}
                <div
                    onDrop={handleDrop}
                    onDragOver={handleDragOver}
                    onClick={() => fileInputRef.current?.click()}
                    className={cn(
                        'flex cursor-pointer flex-col items-center gap-2 rounded-lg border-2 border-dashed p-4',
                        'text-center transition-colors',
                        'border-muted-foreground/25 hover:border-primary/50 hover:bg-muted/50',
                    )}
                >
                    <ImagePlus className="size-6 text-muted-foreground" />
                    <div className="text-sm text-muted-foreground">
                        <span className="font-medium text-primary">
                            Klik untuk unggah
                        </span>{' '}
                        atau seret file ke sini
                    </div>
                    <p className="text-xs text-muted-foreground">
                        Bisa pilih beberapa file sekaligus · Gambar dikompresi
                        otomatis
                    </p>
                    <input
                        ref={fileInputRef}
                        id="media-picker-upload-input"
                        type="file"
                        className="hidden"
                        multiple
                        accept="image/*,application/pdf,.doc,.docx,.xls,.xlsx,.csv,.txt,.md,.zip,.rar,.7z,.mp4,.webm,.mp3,.wav,.svg"
                        onClick={(event) => event.stopPropagation()}
                        onChange={(e) => {
                            handleFileSelect(e.target.files);
                        }}
                    />
                    <Button
                        type="button"
                        variant="outline"
                        size="sm"
                        onClick={(event) => {
                            event.stopPropagation();
                            fileInputRef.current?.click();
                        }}
                    >
                        <Upload className="size-4" />
                        Pilih File
                    </Button>
                </div>

                {/* Upload queue and progress */}
                {uploadQueue.length > 0 && (
                    <div className="space-y-3 rounded-lg border bg-muted/30 p-4">
                        <div className="flex flex-col space-y-1.5 text-left">
                            <h2 className="text-lg font-semibold">
                                Mengunggah Media
                            </h2>
                            <p className="text-sm text-muted-foreground">
                                {isProcessing
                                    ? `Memproses ${uploadQueue.filter((i) => i.status === 'pending' || i.status === 'compressing' || i.status === 'uploading').length} file tersisa...`
                                    : allDone
                                      ? `Selesai — ${doneCount} berhasil, ${errorCount} gagal`
                                      : 'Pratinjau file yang akan diunggah.'}
                            </p>
                        </div>

                        <div className="max-h-[50vh] space-y-2 overflow-y-auto pr-1">
                            {uploadQueue.map((item) => (
                                <div
                                    key={item.id}
                                    className="flex items-center gap-3 rounded-lg border p-3"
                                >
                                    {/* Thumbnail */}
                                    {item.previewUrl ? (
                                        <img
                                            src={item.previewUrl}
                                            alt={item.file.name}
                                            className="size-12 shrink-0 rounded-md object-cover"
                                        />
                                    ) : (
                                        <div className="flex size-12 shrink-0 items-center justify-center rounded-md bg-muted">
                                            <FileType className="size-5 text-muted-foreground" />
                                        </div>
                                    )}


                                    {/* Info */}
                                    <div className="min-w-0 flex-1">
                                        <p
                                            className="truncate text-sm font-medium"
                                            title={item.file.name}
                                        >
                                            {item.file.name}
                                        </p>
                                        <div className="mt-0.5 flex flex-wrap items-center gap-x-2 text-xs text-muted-foreground">
                                            <span>
                                                {formatSize(item.originalSize)}
                                            </span>
                                            {item.savings > 0 && (
                                                <>
                                                    <span>→</span>
                                                    <span className="font-medium text-green-600 dark:text-green-400">
                                                        {formatSize(
                                                            item.compressedSize,
                                                        )}
                                                    </span>
                                                    <span className="rounded-full bg-green-100 px-1.5 py-0 text-[10px] font-medium text-green-700 dark:bg-green-900/30 dark:text-green-400">
                                                        -{item.savings}%
                                                    </span>
                                                </>
                                            )}
                                        </div>
                                        {/* Progress bar */}
                                        {(item.status === 'compressing' ||
                                            item.status === 'uploading' ||
                                            (item.status === 'pending' &&
                                                item.progress === 100)) && (
                                            <div className="mt-1.5 flex items-center gap-2">
                                                <div className="h-1 flex-1 overflow-hidden rounded-full bg-muted">
                                                    <div
                                                        className={`h-full rounded-full transition-[width,background-color] duration-1000 ease-in-out ${
                                                            item.progress ===
                                                            100
                                                                ? 'bg-green-500'
                                                                : 'animate-pulse bg-primary'
                                                        }`}
                                                        style={{
                                                            width: `${item.progress ?? 0}%`,
                                                        }}
                                                    />
                                                </div>
                                                <span className="w-8 text-right text-[10px] text-muted-foreground">
                                                    {item.status ===
                                                    'compressing'
                                                        ? '...'
                                                        : `${item.progress ?? 0}%`}
                                                </span>
                                            </div>
                                        )}
                                    </div>

                                    {/* Status icon */}
                                    <div className="shrink-0">
                                        {item.status === 'pending' && (
                                            <button
                                                type="button"
                                                onClick={() =>
                                                    removeUploadItem(item.id)
                                                }
                                                className="rounded-md p-1 text-muted-foreground hover:text-destructive"
                                            >
                                                <X className="size-4" />
                                            </button>
                                        )}
                                        {item.status === 'compressing' && (
                                            <LoaderCircle className="size-4 animate-spin text-primary" />
                                        )}
                                        {item.status === 'uploading' && (
                                            <button
                                                type="button"
                                                onClick={() =>
                                                    removeUploadItem(item.id)
                                                }
                                                className="rounded-md p-1 text-muted-foreground hover:text-destructive"
                                                aria-label={`Batalkan upload ${item.file.name}`}
                                            >
                                                <X className="size-4" />
                                            </button>
                                        )}
                                        {item.status === 'done' && (
                                            <CheckCircle2 className="size-4 text-green-600 dark:text-green-400" />
                                        )}
                                        {item.status === 'error' && (
                                            <div title={item.error}>
                                                <AlertCircle className="size-4 text-destructive" />
                                            </div>
                                        )}
                                    </div>
                                </div>
                            ))}
                        </div>

                        {/* Actions */}
                        <div className="flex items-center justify-between border-t pt-3">
                            <Button
                                type="button"
                                variant="ghost"
                                size="sm"
                                onClick={cancelAllUploads}
                            >
                                Batalkan Semua
                            </Button>
                            <div className="flex items-center gap-2">
                                {allDone && (
                                    <Button
                                        type="button"
                                        size="sm"
                                        onClick={() => {
                                            uploadQueue.forEach((item) => {
                                                if (item.previewUrl) {
URL.revokeObjectURL(
                                                        item.previewUrl,
                                                    );
}
                                            });
                                            setUploadQueue([]);
                                        }}
                                    >
                                        Selesai
                                    </Button>
                                )}
                                {!isProcessing && hasPending && (
                                    <Button
                                        type="button"
                                        size="sm"
                                        onClick={() =>
                                            void processUploadQueue()
                                        }
                                    >
                                        <Upload className="size-4" />
                                        Unggah{' '}
                                        {
                                            uploadQueue.filter(
                                                (i) => i.status === 'pending',
                                            ).length
                                        }{' '}
                                        File
                                    </Button>
                                )}
                            </div>
                        </div>
                    </div>
                )}



                {showLibrary && (
                    <>
                        {/* Toolbar: pencarian + sort + filter tipe + koleksi */}
                        <div className="flex flex-wrap items-center gap-2">
                            <div className="relative w-64 shrink-0">
                                <Search className="pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-muted-foreground" />
                                <Input
                                    type="search"
                                    value={search}
                                    onChange={(event) =>
                                        handleSearchChange(event.target.value)
                                    }
                                    placeholder="Cari gambar di library..."
                                    aria-label="Cari gambar di library"
                                    className="pl-9"
                                />
                            </div>

                            <Select
                                value={sort}
                                onValueChange={handleSortChange}
                            >
                                <SelectTrigger
                                    className="w-44 whitespace-nowrap"
                                    aria-label="Urutkan berdasarkan"
                                >
                                    <ArrowDownWideNarrow className="size-4 text-muted-foreground" />
                                    <SelectValue placeholder="Terbaru" />
                                </SelectTrigger>
                                <SelectContent>
                                    <SelectItem value="desc">
                                        Terbaru
                                    </SelectItem>
                                    <SelectItem value="asc">Terlama</SelectItem>
                                </SelectContent>
                            </Select>

                            <DropdownMenu>
                                <DropdownMenuTrigger asChild>
                                    <Button
                                        type="button"
                                        variant="outline"
                                        className="min-w-44 gap-1.5 whitespace-nowrap"
                                    >
                                        <FileType className="size-4" />
                                        {selectedLabel}
                                        <ChevronDown className="size-3.5 opacity-60" />
                                    </Button>
                                </DropdownMenuTrigger>
                                <DropdownMenuContent
                                    align="end"
                                    className="max-h-80 w-72 overflow-y-auto"
                                >
                                    <DropdownMenuLabel>
                                        Filter Tipe File
                                    </DropdownMenuLabel>
                                    <DropdownMenuSeparator />
                                    <DropdownMenuCheckboxItem
                                        checked={types.length === 0}
                                        onCheckedChange={clearTypes}
                                    >
                                        Semua tipe
                                    </DropdownMenuCheckboxItem>
                                    {MEDIA_TYPES.map((type) => (
                                        <DropdownMenuCheckboxItem
                                            key={type.key}
                                            checked={types.includes(type.key)}
                                            onCheckedChange={() =>
                                                toggleType(type.key)
                                            }
                                        >
                                            <type.icon className="size-4 text-muted-foreground" />
                                            {type.label}
                                        </DropdownMenuCheckboxItem>
                                    ))}
                                </DropdownMenuContent>
                            </DropdownMenu>

                            <Select
                                value={collection || 'all'}
                                onValueChange={handleCollectionChange}
                            >
                                <SelectTrigger
                                    className="w-48 whitespace-nowrap"
                                    aria-label="Filter Koleksi"
                                >
                                    <FolderOpen className="size-4 text-muted-foreground" />
                                    <SelectValue placeholder="Semua Koleksi" />
                                </SelectTrigger>
                                <SelectContent>
                                    <SelectItem value="all">
                                        Semua Koleksi
                                    </SelectItem>
                                    {availableCollections.map((c) => (
                                        <SelectItem key={c} value={c}>
                                            {c}
                                        </SelectItem>
                                    ))}
                                </SelectContent>
                            </Select>
                        </div>

                        <div className="max-h-[55vh] overflow-y-auto">
                            {loading ? (
                                <div className="flex items-center justify-center gap-2 py-20 text-sm text-muted-foreground">
                                    <LoaderCircle className="size-4 animate-spin" />
                                    Memuat media...
                                </div>
                            ) : items.length === 0 ? (
                                <div className="flex flex-col items-center gap-2 py-20 text-center">
                                    {search ||
                                    types.length > 0 ||
                                    collection ? (
                                        <SearchX className="size-8 text-muted-foreground" />
                                    ) : (
                                        <ImageIcon className="size-8 text-muted-foreground" />
                                    )}
                                    <p className="text-sm text-muted-foreground">
                                        {search ||
                                        types.length > 0 ||
                                        collection
                                            ? 'Tidak ada media yang cocok dengan filter.'
                                            : 'Belum ada media di library.'}
                                    </p>
                                </div>
                            ) : (
                                <div className="grid grid-cols-3 gap-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-8">
                                    {items.map((item) => {
                                        const isSelected = selected.has(
                                            item.id,
                                        );

                                        return (
                                            <button
                                                key={item.id}
                                                type="button"
                                                aria-pressed={isSelected}
                                                onClick={() => openDetail(item)}
                                                className={cn(
                                                    'group relative overflow-hidden rounded-lg border bg-card text-left transition-all',
                                                    'hover:border-primary hover:ring-2 hover:ring-ring',
                                                    isSelected &&
                                                        'border-primary ring-2 ring-ring',
                                                )}
                                            >
                                                <div className="relative flex aspect-square items-center justify-center bg-muted">
                                                    {item.mime?.startsWith(
                                                        'image/',
                                                    ) ? (
                                                        <img
                                                            src={item.thumb_url}
                                                            alt={
                                                                item.alt.id ||
                                                                item.name
                                                            }
                                                            className="size-full object-cover transition-transform group-hover:scale-105"
                                                            loading="lazy"
                                                        />
                                                    ) : (
                                                        <FileType className="size-8 text-muted-foreground" />
                                                    )}
                                                    <span className="absolute right-1.5 bottom-1.5 rounded-md bg-background/80 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground backdrop-blur">
                                                        {formatSize(item.size)}
                                                    </span>
                                                    {multiple && (
                                                        <span
                                                            role="checkbox"
                                                            tabIndex={0}
                                                            aria-checked={
                                                                isSelected
                                                            }
                                                            onClick={(
                                                                event,
                                                            ) => {
                                                                event.stopPropagation();
                                                                toggleSelect(
                                                                    item.id,
                                                                );
                                                            }}
                                                            className={cn(
                                                                'absolute top-1.5 left-1.5 flex size-5 items-center justify-center rounded-full border transition-colors',
                                                                isSelected
                                                                    ? 'border-primary bg-primary text-primary-foreground'
                                                                    : 'border-muted-foreground/40 bg-background/80 backdrop-blur',
                                                            )}
                                                        >
                                                            {isSelected && (
                                                                <Check className="size-3" />
                                                            )}
                                                        </span>
                                                    )}
                                                </div>
                                                <div className="flex items-center gap-1 px-2 py-1.5">
                                                    <p
                                                        className="truncate text-xs text-muted-foreground"
                                                        title={item.name}
                                                    >
                                                        {item.name}
                                                    </p>
                                                    {!multiple && (
                                                        <Check className="ml-auto size-3 shrink-0 text-primary opacity-0 transition-opacity group-hover:opacity-100" />
                                                    )}
                                                </div>
                                            </button>
                                        );
                                    })}
                                </div>
                            )}
                        </div>

                        {!loading && items.length > 0 && lastPage > 1 && (
                            <div className="flex flex-col items-center gap-1">
                                <Pagination>
                                    <PaginationContent>
                                        <PaginationItem>
                                            <PaginationPrevious
                                                href="#"
                                                onClick={(event) => {
                                                    event.preventDefault();
                                                    goToPage(page - 1);
                                                }}
                                                className={cn(
                                                    page <= 1 &&
                                                        'pointer-events-none opacity-40',
                                                )}
                                            />
                                        </PaginationItem>

                                        {pageItems(page, lastPage).map(
                                            (item, index) =>
                                                item === 'ellipsis' ? (
                                                    <PaginationItem
                                                        key={`ellipsis-${index}`}
                                                    >
                                                        <PaginationEllipsis />
                                                    </PaginationItem>
                                                ) : (
                                                    <PaginationItem key={item}>
                                                        <PaginationLink
                                                            href="#"
                                                            isActive={
                                                                item === page
                                                            }
                                                            onClick={(
                                                                event,
                                                            ) => {
                                                                event.preventDefault();
                                                                goToPage(item);
                                                            }}
                                                        >
                                                            {item}
                                                        </PaginationLink>
                                                    </PaginationItem>
                                                ),
                                        )}

                                        <PaginationItem>
                                            <PaginationNext
                                                href="#"
                                                onClick={(event) => {
                                                    event.preventDefault();
                                                    goToPage(page + 1);
                                                }}
                                                className={cn(
                                                    page >= lastPage &&
                                                        'pointer-events-none opacity-40',
                                                )}
                                            />
                                        </PaginationItem>
                                    </PaginationContent>
                                </Pagination>
                                <p className="text-xs text-muted-foreground">
                                    {total} file · Halaman {page} dari{' '}
                                    {lastPage}
                                </p>
                            </div>
                        )}

                        {/* Footer mode multi-pilih */}
                        {multiple && (
                            <div className="flex items-center justify-between gap-2 border-t pt-3">
                                <div className="flex items-center gap-1.5">
                                    <Button
                                        type="button"
                                        variant="outline"
                                        size="sm"
                                        onClick={() =>
                                            setSelected(
                                                new Set(
                                                    items.map(
                                                        (item) => item.id,
                                                    ),
                                                ),
                                            )
                                        }
                                        disabled={items.length === 0}
                                    >
                                        <ListPlus className="size-4" />
                                        Pilih semua halaman
                                    </Button>
                                    {selected.size > 0 && (
                                        <button
                                            type="button"
                                            onClick={handleClearSelection}
                                            className="inline-flex items-center gap-1 text-xs text-muted-foreground transition-colors hover:text-destructive"
                                        >
                                            <X className="size-3.5" />
                                            Kosongkan ({selected.size})
                                        </button>
                                    )}
                                    {selected.size > 0 && (
                                        <Button
                                            type="button"
                                            variant="destructive"
                                            size="sm"
                                            disabled={deletingSelected}
                                            onClick={() =>
                                                setDeleteConfirmOpen(true)
                                            }
                                        >
                                            <Trash2 className="size-3.5" />
                                            {deletingSelected
                                                ? 'Menghapus...'
                                                : 'Hapus terpilih'}
                                        </Button>
                                    )}
                                </div>
                                <Button
                                    type="button"
                                    size="sm"
                                    onClick={handleInsertSelected}
                                    disabled={selected.size === 0}
                                >
                                    <SquareCheckBig className="size-4" />
                                    Sisipkan{' '}
                                    {selected.size > 0
                                        ? `${selected.size} `
                                        : ''}
                                    gambar
                                </Button>
                            </div>
                        )}
                    </>
                )}

                <AlertDialog
                    open={deleteConfirmOpen}
                    onOpenChange={setDeleteConfirmOpen}
                >
                    <AlertDialogContent>
                        <AlertDialogHeader>
                            <AlertDialogTitle>
                                Hapus media terpilih?
                            </AlertDialogTitle>
                            <AlertDialogDescription>
                                {selected.size} file akan dihapus permanen dari
                                Media Library.
                            </AlertDialogDescription>
                        </AlertDialogHeader>
                        <AlertDialogFooter>
                            <AlertDialogCancel disabled={deletingSelected}>
                                Batal
                            </AlertDialogCancel>
                            <AlertDialogAction
                                disabled={deletingSelected}
                                onClick={(event) => {
                                    event.preventDefault();
                                    void handleDeleteSelected();
                                }}
                            >
                                {deletingSelected
                                    ? 'Menghapus...'
                                    : 'Hapus terpilih'}
                            </AlertDialogAction>
                        </AlertDialogFooter>
                    </AlertDialogContent>
                </AlertDialog>
            </DialogContent>
        </Dialog>

            {/* Detail file media — Dialog terpisah di atas Library Media agar tidak tertimpa stacking context */}
            <Dialog open={!!detailItem} onOpenChange={(o) => !o && setDetailItem(null)}>
                <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-2xl [&>button]:z-10">
                    {detailItem && (
                        <>
                            <DialogHeader>
                                <DialogTitle className="break-all pr-6">{detailItem.name}</DialogTitle>
                                <DialogDescription>Detail file media &amp; pemakaiannya di konten.</DialogDescription>
                            </DialogHeader>
                            <div className="grid gap-5 md:grid-cols-2">
                                <div className="flex min-h-64 items-center justify-center rounded-lg border bg-muted">
                                    {detailItem.mime?.startsWith('image/') ? (
                                        <img src={detailItem.url} alt={detailItem.name} className="max-h-96 w-full object-contain" />
                                    ) : (
                                        <FileType className="size-16 text-muted-foreground" />
                                    )}
                                </div>
                                <div className="space-y-4">
                                    <dl className="grid grid-cols-[auto_1fr] gap-x-4 gap-y-2 text-sm">
                                        <dt className="text-muted-foreground">Tipe</dt>
                                        <dd className="break-all">{detailItem.mime ?? '—'}</dd>
                                        <dt className="text-muted-foreground">Ukuran</dt>
                                        <dd>{formatSize(detailItem.size)}</dd>
                                        <dt className="text-muted-foreground">Dimensi</dt>
                                        <dd>{detailItem.width && detailItem.height ? `${detailItem.width} × ${detailItem.height} px` : '—'}</dd>
                                        <dt className="text-muted-foreground">Koleksi</dt>
                                        <dd>{detailItem.collection}</dd>
                                        <dt className="text-muted-foreground">Diunggah</dt>
                                        <dd>{detailItem.created_at ?? '—'}</dd>
                                    </dl>
                                    <div className="rounded-lg border bg-muted/40 p-3 text-sm">
                                        <p className="font-medium">{detailItem.usage?.in_use ? 'Dipakai oleh:' : 'Tidak dipakai konten mana pun.'}</p>
                                        {detailItem.usage?.in_use && (
                                            <ul className="mt-1 list-disc pl-5 text-muted-foreground">
                                                {[...(detailItem.usage?.attached ?? []), ...(detailItem.usage?.referenced ?? [])].map((where) => (
                                                    <li key={where}>{where}</li>
                                                ))}
                                            </ul>
                                        )}
                                    </div>
                                    <div className="space-y-1.5">
                                        <div className="flex items-center justify-between">
                                            <p className="text-sm font-medium">Alt Text</p>
                                            <Button type="button" variant="ghost" size="sm" onClick={() => setEditingAlt((v) => !v)}>
                                                {editingAlt ? 'Batal' : 'Edit Alt'}
                                            </Button>
                                        </div>
                                        {editingAlt ? (
                                            <div className="space-y-2">
                                                <Input value={altDraft.id} onChange={(e) => setAltDraft((v) => ({ ...v, id: e.target.value }))} placeholder="Alt text Indonesia" />
                                                <Input value={altDraft.en} onChange={(e) => setAltDraft((v) => ({ ...v, en: e.target.value }))} placeholder="Alt text English" />
                                                <Button type="button" size="sm" disabled={savingAlt} onClick={() => saveAlt()}>
                                                    {savingAlt ? 'Menyimpan...' : 'Simpan Alt'}
                                                </Button>
                                            </div>
                                        ) : (
                                            <>
                                                <p className="rounded-md border px-2.5 py-1.5 text-sm text-muted-foreground"><span className="font-medium text-foreground">ID:</span> {detailItem.alt.id || '—'}</p>
                                                <p className="rounded-md border px-2.5 py-1.5 text-sm text-muted-foreground"><span className="font-medium text-foreground">EN:</span> {detailItem.alt.en || '—'}</p>
                                            </>
                                        )}
                                    </div>
                                </div>
                            </div>
                            <div className="flex flex-wrap justify-end gap-2 pt-2">
                                <Button variant="outline" size="sm" asChild>
                                    <a href={detailItem.url} target="_blank" rel="noreferrer">
                                        <Download className="size-4" /> Unduh
                                    </a>
                                </Button>
                                <Button variant="ghost" size="sm" onClick={() => setDetailItem(null)}>
                                    Tutup
                                </Button>
                                <Button
                                    size="sm"
                                    onClick={() => {
                                        handleSelect(detailItem);
                                        setDetailItem(null);
                                    }}
                                >
                                    Pilih
                                </Button>
                            </div>
                        </>
                    )}
                </DialogContent>
            </Dialog>
        </>
    );
}
