import FilterBar from '@/Components/catalog/FilterBar';
import { activeKinds, clean, clearAll, Filters, SORTS } from '@/Components/catalog/filters';
import { CardVariant } from '@/Components/game/GameCard';
import GameGrid from '@/Components/game/GameGrid';
import { GameGridSkeleton } from '@/Components/game/GameSkeleton';
import EmptyState from '@/Components/shared/EmptyState';
import Seo from '@/Components/shared/Seo';
import { Button } from '@/Components/ui/button';
import { useDebounce } from '@/hooks/useDebounce';
import { useNavigating } from '@/hooks/useNavigating';
import PublicLayout from '@/Layouts/PublicLayout';
import { cn } from '@/lib/utils';
import { Facets, GameCard } from '@/types/models';
import { InfiniteScroll, router } from '@inertiajs/react';
import { LayoutGrid, List, Search, SearchX, X } from 'lucide-react';
import { useEffect, useRef, useState } from 'react';

type Props = { games: { data: GameCard[] }; total: number; filters: Filters; featured: { data: GameCard[] } | never[]; facets?: Facets };

const readView = (): CardVariant => {
    try { return localStorage.getItem('aether:view') === 'list' ? 'list' : 'grid'; } catch { return 'grid'; }
};

export default function Index({ games, total, filters, featured, facets }: Props) {
    const [q, setQ] = useState(filters.q ?? '');
    const dq = useDebounce(q, 250);
    const first = useRef(true);
    const busy = useNavigating(120);
    const [view, setView] = useState<CardVariant>('grid');
    useEffect(() => setView(readView()), []);

    const kinds = activeKinds(filters);
    const pristine = kinds.length === 0 && !filters.q;
    const featuredList = 'data' in featured ? featured.data : [];

    const visit = (next: Filters) => {
        const query = clean(next);
        const willBePristine = Object.keys(query).filter((k) => k !== 'sort').length === 0;
        router.get(route('catalog'), query as Record<string, any>, {
            preserveState: true,
            preserveScroll: true,
            replace: true,
            only: ['games', 'total', 'filters', ...(willBePristine ? ['featured'] : [])],
            reset: ['games'],
        });
    };

    // keep local search box in sync when filters are cleared externally
    useEffect(() => { if ((filters.q ?? '') !== q && !busy) setQ(filters.q ?? ''); }, [filters.q]);

    useEffect(() => {
        if (first.current) { first.current = false; return; }
        if ((dq || undefined) !== (filters.q || undefined)) visit({ ...filters, q: dq || undefined });
    }, [dq]);

    const setViewMode = (v: CardVariant) => { setView(v); try { localStorage.setItem('aether:view', v); } catch {} };
    const sortValue = filters.sort ?? (filters.q ? 'relevance' : 'popular');

    return (
        <PublicLayout>
            <Seo title="Browse games" />
            <div className="space-y-6">
                <header className="flex flex-wrap items-end justify-between gap-3">
                    <div>
                        <h1 className="text-h1">Games</h1>
                        <p className="mt-1 text-sm text-muted-foreground" aria-live="polite">{total.toLocaleString()} {total === 1 ? 'game' : 'games'}{!pristine && ' match'}</p>
                    </div>
                </header>

                {pristine && featuredList.length > 0 && (
                    <section aria-label="Featured" className="space-y-3">
                        <h2 className="text-overline">Featured</h2>
                        <GameGrid games={featuredList} variant="featured" />
                    </section>
                )}

                <div className="sticky top-14 z-30 -mx-4 space-y-3 border-b border-border bg-background/80 px-4 py-3 backdrop-blur-xl sm:-mx-6 sm:px-6">
                    <div className="flex flex-wrap items-center gap-2">
                        <div className="relative min-w-[200px] flex-1">
                            <Search className="absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
                            <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search titles, developers…" aria-label="Search games" maxLength={80} className="h-10 w-full rounded-lg border border-input bg-card/60 pl-9 pr-9 text-sm outline-none transition placeholder:text-muted-foreground/70 focus:border-ring focus:ring-4 focus:ring-ring/15" />
                            {q && <button onClick={() => setQ('')} aria-label="Clear search" className="absolute right-2 top-1/2 -translate-y-1/2 rounded p-1 text-muted-foreground hover:text-foreground"><X className="size-3.5" /></button>}
                        </div>
                        <select aria-label="Sort" value={sortValue} onChange={(e) => visit({ ...filters, sort: e.target.value })} className="h-10 rounded-lg border border-input bg-card/60 px-3 text-sm outline-none focus:border-ring focus:ring-4 focus:ring-ring/15">
                            {filters.q && <option value="relevance">Relevance</option>}
                            {SORTS.map(([v, l]) => <option key={v} value={v}>{l}</option>)}
                        </select>
                        <div className="inline-flex rounded-lg border border-border bg-card/60 p-0.5" role="group" aria-label="View">
                            {([['grid', LayoutGrid], ['list', List]] as const).map(([v, Icon]) => (
                                <button key={v} aria-pressed={view === v} aria-label={`${v} view`} onClick={() => setViewMode(v)} className={cn('rounded-md p-2 transition', view === v ? 'bg-accent text-foreground' : 'text-muted-foreground hover:text-foreground')}><Icon className="size-4" /></button>
                            ))}
                        </div>
                    </div>
                    <FilterBar filters={filters} facets={facets} onChange={visit} />
                </div>

                <div className={cn('transition-opacity duration-200', busy && 'pointer-events-none opacity-50')} aria-busy={busy}>
                    {games.data.length ? (
                        <InfiniteScroll data="games" loading={<div className="pt-4"><GameGridSkeleton variant={view} count={view === 'list' ? 3 : 5} /></div>}>
                            <GameGrid games={games.data} variant={view} />
                        </InfiniteScroll>
                    ) : busy ? (
                        <GameGridSkeleton variant={view} count={view === 'list' ? 6 : 10} />
                    ) : (
                        <EmptyState icon={SearchX} title="No games match" description="Try removing a filter or searching for something broader." action={<Button variant="secondary" onClick={() => { setQ(''); visit(clearAll({ sort: filters.sort })); }}>Reset filters</Button>} />
                    )}
                </div>
            </div>
        </PublicLayout>
    );
}
