import ConfirmDialog from '@/Components/admin/ConfirmDialog';
import { ImageField, MultiSelectField, ScreenshotsField, selectClass, Switch } from '@/Components/admin/fields';
import { Card } from '@/Components/admin/primitives';
import { Button } from '@/Components/ui/button';
import { Field, Input, Textarea } from '@/Components/ui/field';
import AdminLayout from '@/Layouts/AdminLayout';
import { Option } from '@/types/admin';
import { Head, Link, router, useForm } from '@inertiajs/react';
import { ArrowLeft, ExternalLink, Trash2 } from 'lucide-react';
import { FormEventHandler, useState } from 'react';

type Spec = Partial<Record<'os' | 'processor' | 'memory' | 'graphics' | 'storage', string>>;
type GameData = {
    id: number; title: string; slug: string; summary: string | null; description: string | null; status: string; release_date: string | null;
    metacritic: number | null; playtime_main: number | null; playtime_complete: number | null; age_rating: string | null; website_url: string | null; trailer_url: string | null;
    developer_id: number | null; publisher_id: number | null; is_featured: boolean; genres: number[]; platforms: number[]; tags: number[];
    system_requirements: { minimum?: Spec; recommended?: Spec } | null; cover: string | null; hero: string | null; screenshots: { id: number; thumb: string }[]; public_url: string;
};
type Props = { game: GameData | null; companies: Option[]; genres: Option[]; platforms: Option[]; tags: Option[]; statuses: string[] };

const SPEC_FIELDS = [['os', 'OS'], ['processor', 'Processor'], ['memory', 'Memory'], ['graphics', 'Graphics'], ['storage', 'Storage']] as const;
const s = (v: unknown) => (v === null || v === undefined ? '' : String(v));

export default function Form({ game, companies, genres, platforms, tags, statuses }: Props) {
    const editing = !!game;
    const { data, setData, post, processing, errors, isDirty } = useForm({
        _method: editing ? 'put' : 'post',
        title: game?.title ?? '', slug: game?.slug ?? '', summary: s(game?.summary), description: s(game?.description),
        release_date: s(game?.release_date), status: game?.status ?? 'draft',
        developer_id: s(game?.developer_id), publisher_id: s(game?.publisher_id),
        genres: game?.genres ?? ([] as number[]), platforms: game?.platforms ?? ([] as number[]), tags: game?.tags ?? ([] as number[]),
        metacritic: s(game?.metacritic), playtime_main: s(game?.playtime_main), playtime_complete: s(game?.playtime_complete),
        age_rating: s(game?.age_rating), website_url: s(game?.website_url), trailer_url: s(game?.trailer_url),
        is_featured: game?.is_featured ?? false,
        system_requirements: { minimum: { ...game?.system_requirements?.minimum }, recommended: { ...game?.system_requirements?.recommended } } as { minimum: Spec; recommended: Spec },
        cover: null as File | null, hero: null as File | null, remove_cover: false, remove_hero: false,
        screenshots: [] as File[], remove_screenshots: [] as number[],
    });
    const [confirmDelete, setConfirmDelete] = useState(false);
    const err = errors as Record<string, string>;

    const submit: FormEventHandler = (e) => {
        e.preventDefault();
        post(editing ? route('admin.games.update', game!.slug) : route('admin.games.store'), { forceFormData: true, preserveScroll: true });
    };
    const spec = (tier: 'minimum' | 'recommended', key: keyof Spec, v: string) => setData('system_requirements', { ...data.system_requirements, [tier]: { ...data.system_requirements[tier], [key]: v } });
    const num = (k: 'metacritic' | 'playtime_main' | 'playtime_complete', label: string, max: number) => (
        <Field label={label} htmlFor={k} error={err[k]}><Input id={k} type="number" inputMode="numeric" min={0} max={max} value={data[k]} onChange={(e) => setData(k, e.target.value)} /></Field>
    );

    return (
        <AdminLayout>
            <Head title={editing ? `Edit ${game!.title}` : 'New game'} />
            <form onSubmit={submit} noValidate>
                <div className="sticky top-0 z-20 -mx-4 mb-6 flex flex-wrap items-center gap-3 border-b border-border bg-background/80 px-4 py-3 backdrop-blur-xl sm:-mx-8 sm:px-8 lg:top-0">
                    <Link href={route('admin.games.index')} aria-label="Back to games" className="rounded-lg p-2 text-muted-foreground hover:bg-accent hover:text-foreground"><ArrowLeft className="size-4" /></Link>
                    <div className="min-w-0 flex-1">
                        <h1 className="truncate text-h3">{editing ? game!.title : 'New game'}</h1>
                        {isDirty && <p className="text-caption">Unsaved changes</p>}
                    </div>
                    {editing && <a href={game!.public_url} target="_blank" rel="noreferrer" className="hidden items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground sm:inline-flex">View <ExternalLink className="size-3.5" /></a>}
                    {editing && <Button type="button" variant="ghost" onClick={() => setConfirmDelete(true)} className="text-destructive hover:text-destructive"><Trash2 />Trash</Button>}
                    <Button type="submit" loading={processing}>{editing ? 'Save changes' : 'Create game'}</Button>
                </div>

                <div className="grid gap-5 lg:grid-cols-[minmax(0,1fr)_320px]">
                    <div className="space-y-5">
                        <Card title="Basics">
                            <div className="space-y-4">
                                <Field label="Title" htmlFor="title" error={err.title}><Input id="title" autoFocus={!editing} value={data.title} onChange={(e) => setData('title', e.target.value)} aria-invalid={!!err.title} /></Field>
                                <Field label="URL slug" htmlFor="slug" error={err.slug} hint="Leave blank to generate from the title."><Input id="slug" value={data.slug} onChange={(e) => setData('slug', e.target.value)} placeholder="auto-generated" /></Field>
                                <Field label="Summary" htmlFor="summary" error={err.summary} hint={`${data.summary.length}/500 · shown on cards and in search`}><Textarea id="summary" rows={2} maxLength={500} value={data.summary} onChange={(e) => setData('summary', e.target.value)} /></Field>
                                <Field label="Description" htmlFor="description" error={err.description} hint="Plain text. Separate paragraphs with a blank line."><Textarea id="description" rows={9} value={data.description} onChange={(e) => setData('description', e.target.value)} /></Field>
                            </div>
                        </Card>

                        <Card title="Media" description="JPG, PNG or WebP. Conversions are generated automatically.">
                            <div className="grid gap-5 sm:grid-cols-[180px_1fr]">
                                <ImageField label="Cover" hint="3:4, up to 5 MB" current={game?.cover ?? null} file={data.cover} removed={data.remove_cover} onFile={(f) => setData('cover', f)} onRemove={(r) => setData('remove_cover', r)} error={err.cover} />
                                <ImageField label="Hero banner" hint="Wide, up to 8 MB" aspect="aspect-[16/9] sm:aspect-auto sm:h-full sm:min-h-44" current={game?.hero ?? null} file={data.hero} removed={data.remove_hero} onFile={(f) => setData('hero', f)} onRemove={(r) => setData('remove_hero', r)} error={err.hero} />
                            </div>
                            <div className="mt-5">
                                <ScreenshotsField existing={game?.screenshots ?? []} removeIds={data.remove_screenshots} onToggleRemove={(id) => setData('remove_screenshots', data.remove_screenshots.includes(id) ? data.remove_screenshots.filter((i) => i !== id) : [...data.remove_screenshots, id])} files={data.screenshots} onFiles={(f) => setData('screenshots', f)} error={err.screenshots ?? err['screenshots.0']} />
                            </div>
                        </Card>

                        <Card title="Details">
                            <div className="grid gap-4 sm:grid-cols-3">
                                <Field label="Release date" htmlFor="release_date" error={err.release_date}><Input id="release_date" type="date" value={data.release_date} onChange={(e) => setData('release_date', e.target.value)} /></Field>
                                {num('metacritic', 'Metacritic', 100)}
                                <Field label="Age rating" htmlFor="age_rating" error={err.age_rating}><Input id="age_rating" maxLength={8} value={data.age_rating} onChange={(e) => setData('age_rating', e.target.value)} placeholder="E, T, M…" /></Field>
                                {num('playtime_main', 'Main story (hours)', 2000)}
                                {num('playtime_complete', 'Completionist (hours)', 5000)}
                            </div>
                            <div className="mt-4 grid gap-4 sm:grid-cols-2">
                                <Field label="Website" htmlFor="website_url" error={err.website_url}><Input id="website_url" type="url" value={data.website_url} onChange={(e) => setData('website_url', e.target.value)} placeholder="https://" /></Field>
                                <Field label="Trailer (YouTube)" htmlFor="trailer_url" error={err.trailer_url}><Input id="trailer_url" type="url" value={data.trailer_url} onChange={(e) => setData('trailer_url', e.target.value)} placeholder="https://youtube.com/watch?v=…" /></Field>
                            </div>
                        </Card>

                        <Card title="System requirements" description="Optional. Leave a tier empty to hide it.">
                            <div className="grid gap-6 sm:grid-cols-2">
                                {(['minimum', 'recommended'] as const).map((tier) => (
                                    <fieldset key={tier} className="space-y-3">
                                        <legend className="text-overline mb-2 capitalize">{tier}</legend>
                                        {SPEC_FIELDS.map(([k, label]) => (
                                            <Field key={k} label={label} htmlFor={`${tier}-${k}`} error={err[`system_requirements.${tier}.${k}`]}>
                                                <Input id={`${tier}-${k}`} maxLength={200} value={data.system_requirements[tier][k] ?? ''} onChange={(e) => spec(tier, k, e.target.value)} />
                                            </Field>
                                        ))}
                                    </fieldset>
                                ))}
                            </div>
                        </Card>
                    </div>

                    <div className="space-y-5 lg:sticky lg:top-24 lg:self-start">
                        <Card title="Publishing">
                            <div className="space-y-4">
                                <Field label="Status" htmlFor="status" error={err.status}>
                                    <select id="status" value={data.status} onChange={(e) => setData('status', e.target.value)} className={`${selectClass} capitalize`}>{statuses.map((st) => <option key={st}>{st}</option>)}</select>
                                </Field>
                                <Switch label="Featured on catalog" checked={data.is_featured} onChange={(v) => setData('is_featured', v)} />
                            </div>
                        </Card>
                        <Card title="Relations">
                            <div className="space-y-5">
                                <Field label="Developer" htmlFor="developer_id" error={err.developer_id}>
                                    <select id="developer_id" value={data.developer_id} onChange={(e) => setData('developer_id', e.target.value)} className={selectClass}><option value="">None</option>{companies.map((c) => <option key={c.id} value={c.id}>{c.name}</option>)}</select>
                                </Field>
                                <Field label="Publisher" htmlFor="publisher_id" error={err.publisher_id}>
                                    <select id="publisher_id" value={data.publisher_id} onChange={(e) => setData('publisher_id', e.target.value)} className={selectClass}><option value="">None</option>{companies.map((c) => <option key={c.id} value={c.id}>{c.name}</option>)}</select>
                                </Field>
                                <Field label="Genres" error={err.genres}><MultiSelectField options={genres} value={data.genres} onChange={(v) => setData('genres', v)} placeholder="Add genre" /></Field>
                                <Field label="Platforms" error={err.platforms}><MultiSelectField options={platforms} value={data.platforms} onChange={(v) => setData('platforms', v)} placeholder="Add platform" /></Field>
                                <Field label="Tags" error={err.tags}><MultiSelectField options={tags} value={data.tags} onChange={(v) => setData('tags', v)} placeholder="Add tag" /></Field>
                            </div>
                        </Card>
                    </div>
                </div>
            </form>

            {editing && (
                <ConfirmDialog open={confirmDelete} danger title={`Move “${game!.title}” to trash?`} description="It disappears from the site and search. You can restore it from Trash." confirmLabel="Move to trash" onClose={() => setConfirmDelete(false)} onConfirm={() => router.delete(route('admin.games.destroy', game!.slug))} />
            )}
        </AdminLayout>
    );
}
