import { Head, Link, setLayoutProps } from '@inertiajs/react';

import {
    ChevronLeft,
    FileText,
    Image as ImageIcon,
    Search,
} from 'lucide-react';

import { useEffect, useMemo, useState } from 'react';

import { FileGrid } from '@/components/media/FileGrid';
import { FolderGrid } from '@/components/media/FolderGrid';
import { MediaDetailDialog } from '@/components/media/MediaDetailDialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';

import { index as mediaIndex } from '@/routes/media/index';
import type { MediaFile, TaskFolder } from '@/types/media';

interface Props {
    data: {
        project: {
            id: number;
            name: string;
            is_division?: boolean;
        };
        media: MediaFile[];
        // Folder task yang dibuka menurut server (dari query ?folder=). Dipakai
        // untuk init state agar tampilan awal langsung benar tanpa flash.
        active_folder?: string | null;
    };
}

const FILE_TYPE_FILTERS = [
    { value: 'all', label: 'All', icon: null },
    { value: 'image', label: 'Images', icon: ImageIcon },
    { value: 'document', label: 'Documents', icon: FileText },
] as const;

type FileTypeFilter = (typeof FILE_TYPE_FILTERS)[number]['value'];

/** Nama query param yang menyimpan folder task yang sedang dibuka. */
const FOLDER_QUERY_PARAM = 'folder';

/**
 * Tulis folder yang sedang dibuka ke URL tanpa reload. null berarti kembali ke
 * daftar folder, sehingga param dihapus dari URL.
 *
 * `push` menambah entri history baru — dipakai saat masuk folder agar tombol
 * Back browser mengembalikan user ke daftar folder, bukan keluar dari halaman.
 * Tanpa `push`, URL ditimpa di tempat (keluar folder / bersihkan param yatim).
 *
 * `window.history.state` diteruskan apa adanya, bukan ditimpa `{}`, supaya
 * snapshot halaman milik Inertia tetap utuh di entri history yang baru.
 */
function writeFolderKeyToUrl(key: string | null, push = false): void {
    if (typeof window === 'undefined') {
        return;
    }

    const url = new URL(window.location.href);

    if (key) {
        url.searchParams.set(FOLDER_QUERY_PARAM, key);
    } else {
        url.searchParams.delete(FOLDER_QUERY_PARAM);
    }

    if (push) {
        window.history.pushState(window.history.state, '', url.toString());
    } else {
        window.history.replaceState(window.history.state, '', url.toString());
    }
}

/** Folder yang sedang dibuka menurut URL saat ini. */
function readFolderKeyFromUrl(): string | null {
    return new URL(window.location.href).searchParams.get(FOLDER_QUERY_PARAM);
}

/**
 * Kelompokkan file menjadi folder per task. File tanpa task disatukan ke folder
 * "Tanpa Task" agar tetap dapat diakses. Folder & file diurutkan dari yang
 * paling baru diperbarui.
 */
function groupFilesIntoFolders(media: MediaFile[]): TaskFolder[] {
    const folders = new Map<string, TaskFolder>();

    for (const file of media) {
        const key = file.task_code || file.task_name || 'no-task';
        const name = file.task_name || file.task_code || 'No Task';

        const folder = folders.get(key) ?? {
            key,
            name,
            files: [],
            updatedAt: file.updated_at,
        };

        folder.files.push(file);

        if (file.updated_at > folder.updatedAt) {
            folder.updatedAt = file.updated_at;
        }

        folders.set(key, folder);
    }

    return Array.from(folders.values())
        .map((folder) => ({
            ...folder,
            files: [...folder.files].sort((a, b) =>
                b.updated_at.localeCompare(a.updated_at),
            ),
        }))
        .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
}

export default function MediaShow({ data }: Props) {
    const [searchQuery, setSearchQuery] = useState('');
    const [filterType, setFilterType] = useState<FileTypeFilter>('all');
    // Init dari prop server (bukan window) agar tampilan awal langsung benar
    // tanpa flash saat refresh; navigasi berikutnya menyinkronkan URL sendiri.
    const [openFolderKey, setOpenFolderKey] = useState<string | null>(
        data.active_folder ?? null,
    );
    const [selectedMedia, setSelectedMedia] = useState<MediaFile | null>(null);
    const [isDetailOpen, setIsDetailOpen] = useState(false);

    const folders = useMemo(
        () => groupFilesIntoFolders(data.media),
        [data.media],
    );

    const openFolder = useMemo(
        () => folders.find((folder) => folder.key === openFolderKey) ?? null,
        [folders, openFolderKey],
    );

    // Folder di URL bisa tidak valid lagi (mis. task/file-nya dihapus). Saat itu
    // terjadi, openFolder = null → tampilan otomatis jatuh ke daftar folder;
    // effect ini hanya membersihkan param yatim di URL (sistem eksternal), bukan
    // mengubah state React, agar konsisten dengan tampilan.
    useEffect(() => {
        if (openFolderKey !== null && openFolder === null) {
            writeFolderKeyToUrl(null);
        }
    }, [openFolderKey, openFolder]);

    // Back/Forward browser hanya mengubah URL — state folder harus ikut
    // disinkronkan agar tampilan tetap cocok dengan URL.
    useEffect(() => {
        const syncFromUrl = () => setOpenFolderKey(readFolderKeyFromUrl());

        window.addEventListener('popstate', syncFromUrl);

        return () => window.removeEventListener('popstate', syncFromUrl);
    }, []);

    const query = searchQuery.trim().toLowerCase();

    // Di tampilan grid folder, pencarian menyaring folder berdasarkan nama task.
    const filteredFolders = useMemo(
        () =>
            folders.filter((folder) =>
                folder.name.toLowerCase().includes(query),
            ),
        [folders, query],
    );

    // Di dalam folder, pencarian & filter tipe menyaring file folder tersebut.
    const filteredFiles = useMemo(() => {
        if (!openFolder) {
            return [];
        }

        return openFolder.files.filter((file) => {
            const matchesSearch = file.name.toLowerCase().includes(query);
            const matchesType =
                filterType === 'all' || file.type === filterType;

            return matchesSearch && matchesType;
        });
    }, [openFolder, query, filterType]);

    const enterFolder = (key: string) => {
        setOpenFolderKey(key);
        writeFolderKeyToUrl(key, true);
        setSearchQuery('');
        setFilterType('all');
    };

    const backToFolders = () => {
        setOpenFolderKey(null);
        writeFolderKeyToUrl(null);
        setSearchQuery('');
        setFilterType('all');
    };

    const openDownload = (file: MediaFile) => {
        window.open(
            file.download_url || file.url || '#',
            '_blank',
            'noopener,noreferrer',
        );
    };

    // Breadcrumb mengikuti posisi user: folder yang sedang dibuka jadi crumb
    // terakhir. Crumb project sengaja tanpa href — keluar folder ditangani
    // tombol "Back to folder list" di halaman (murni client-side), sedangkan
    // Link Inertia akan memicu request dan bisa membuat state folder tak sinkron.
    setLayoutProps({
        breadcrumbs: [
            { title: 'Media', href: mediaIndex().url },
            { title: data.project.name },
            ...(openFolder ? [{ title: openFolder.name }] : []),
        ],
    });

    return (
        <>
            <Head title={`Media - ${data.project.name}`} />

            <div className="flex flex-col gap-8 p-6 lg:p-8">
                {/* Header Section */}
                <div className="flex flex-col gap-4">
                    {openFolder ? (
                        <button
                            type="button"
                            onClick={backToFolders}
                            className="flex w-fit cursor-pointer items-center gap-2 text-sm text-muted-foreground hover:text-primary"
                        >
                            <ChevronLeft size={16} /> Back to folder list
                        </button>
                    ) : (
                        <Link
                            href={mediaIndex().url}
                            className="flex w-fit items-center gap-2 text-sm text-muted-foreground hover:text-primary"
                        >
                            <ChevronLeft size={16} /> Back to Media Repository
                        </Link>
                    )}
                    <div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
                        <div className="flex flex-col gap-1">
                            <h1 className="text-2xl font-bold tracking-tight md:text-3xl">
                                {openFolder
                                    ? openFolder.name
                                    : data.project.name}
                            </h1>
                            <p className="text-muted-foreground">
                                {openFolder
                                    ? `${openFolder.files.length} file dalam task ini.`
                                    : data.project.is_division
                                      ? 'Showing all media from non-project tasks in this division, grouped by task.'
                                      : 'Showing all media and attachments from this project, grouped by task.'}
                            </p>
                        </div>
                    </div>
                </div>

                {/* Filters & Search */}
                <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
                    <div className="relative w-full sm:max-w-xs">
                        <Search
                            className="absolute top-1/2 left-3 -translate-y-1/2 text-muted-foreground"
                            size={18}
                        />
                        <Input
                            placeholder={
                                openFolder
                                    ? 'Search files...'
                                    : 'Search task folders...'
                            }
                            className="pl-10"
                            value={searchQuery}
                            onChange={(e) => setSearchQuery(e.target.value)}
                        />
                    </div>
                    {/* Filter tipe hanya relevan saat melihat isi folder. */}
                    {openFolder && (
                        <div className="flex items-center gap-2 overflow-x-auto pb-2 sm:pb-0">
                            {FILE_TYPE_FILTERS.map((filter) => {
                                const Icon = filter.icon;

                                return (
                                    <Button
                                        key={filter.value}
                                        variant={
                                            filterType === filter.value
                                                ? 'default'
                                                : 'outline'
                                        }
                                        size="sm"
                                        onClick={() =>
                                            setFilterType(filter.value)
                                        }
                                        className={Icon ? 'gap-2' : undefined}
                                    >
                                        {Icon && <Icon size={16} />}
                                        {filter.label}
                                    </Button>
                                );
                            })}
                        </div>
                    )}
                </div>

                {/* Folder grid / File grid */}
                {openFolder ? (
                    <FileGrid
                        files={filteredFiles}
                        onView={(file) => {
                            setSelectedMedia(file);
                            setIsDetailOpen(true);
                        }}
                    />
                ) : (
                    <FolderGrid
                        folders={filteredFolders}
                        onOpen={enterFolder}
                    />
                )}
            </div>

            <MediaDetailDialog
                media={selectedMedia}
                open={isDetailOpen}
                onOpenChange={setIsDetailOpen}
                onDownload={() => {
                    if (selectedMedia) {
                        openDownload(selectedMedia);
                    }
                }}
            />
        </>
    );
}
