import { Head, router, useForm } from '@inertiajs/react';
import { Check, ChevronsUpDown, Pencil, Trophy, Trash2 } from 'lucide-react';
import { FormEvent, useState } from 'react';
import { toast } from 'sonner';

import ConfirmDialog from '@/components/dashboard/ConfirmDialog';
import { FileInput } from '@/components/ui/file-input';
import DashboardLayout from '@/components/dashboard/DashboardLayout';
import { DashboardPageHeader } from '@/components/dashboard/DashboardPageHeader';
import DataTable, { Column, Paginator } from '@/components/dashboard/DataTable';
import { DateTimePicker } from '@/components/DatePicker';
import FormDialog from '@/components/dashboard/FormDialog';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
    Command,
    CommandEmpty,
    CommandGroup,
    CommandInput,
    CommandItem,
    CommandList,
} from '@/components/ui/command';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Switch } from '@/components/ui/switch';
import { Textarea } from '@/components/ui/textarea';
import { useTranslation } from '@/contexts/LanguageContext';
import { formatNumber } from '@/lib/format';
import { cn } from '@/lib/utils';

interface GameOption {
    id: number;
    title: string;
    thumbnail?: Record<string, string> | null;
}

interface TournamentRow {
    id: number;
    title: string;
    slug: string;
    description: string | null;
    image: Record<string, string> | null;
    game_id: number;
    game: GameOption | null;
    status: string;
    entry_fee_gp: number;
    prize_gp: number;
    winner_count: number;
    prize_distribution: Record<string, number> | null;
    max_participants: number | null;
    entries_count: number;
    starts_at: string | null;
    ends_at: string | null;
    registration_opens_at: string | null;
    registration_closes_at: string | null;
    is_active: boolean;
    auto_manage: boolean;
}

interface Props {
    rows: Paginator<TournamentRow>;
    filters: { search?: string };
    games: GameOption[];
    statuses: string[];
}

function labelFor(value: string): string {
    return value.split('_').map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(' ');
}

export default function TournamentsIndex({ rows, filters, games, statuses }: Props) {
    const { t } = useTranslation();
    const [createOpen, setCreateOpen] = useState(false);
    const [editTarget, setEditTarget] = useState<TournamentRow | null>(null);
    const [deleteTarget, setDeleteTarget] = useState<TournamentRow | null>(null);
    const [awardTarget, setAwardTarget] = useState<TournamentRow | null>(null);

    const columns: Column<TournamentRow>[] = [
        {
            key: 'title',
            label: t('Tournament'),
            cell: (row) => (
                <div className="flex flex-col">
                    <span className="font-medium">{row.title}</span>
                    <span className="text-xs text-muted-foreground">{row.game?.title ?? t('No game')}</span>
                </div>
            ),
        },
        {
            key: 'status',
            label: t('Status'),
            cell: (row) => <Badge variant={row.is_active ? 'default' : 'secondary'}>{t(labelFor(row.status))}</Badge>,
        },
        {
            key: 'entries',
            label: t('Entries'),
            cell: (row) => <span className="tabular-nums">{row.entries_count}</span>,
        },
        {
            key: 'prize',
            label: t('Prize pool'),
            cell: (row) => <span className="tabular-nums">{formatNumber(row.prize_gp)} GP</span>,
        },
    ];

    function destroy() {
        if (!deleteTarget) return;
        router.delete(`/dashboard/tournaments/${deleteTarget.id}`, {
            preserveScroll: true,
            onSuccess: () => {
                toast.success(t('Tournament deleted'));
                setDeleteTarget(null);
            },
        });
    }

    function awardPrizes() {
        if (!awardTarget) return;
        router.post(`/dashboard/tournaments/${awardTarget.id}/award-prizes`, {}, {
            preserveScroll: true,
            onSuccess: () => {
                toast.success(t('Prizes awarded'));
                setAwardTarget(null);
            },
        });
    }

    return (
        <DashboardLayout>
            <Head title={t('Tournaments')} />
            <DashboardPageHeader
                title={t('Tournaments')}
                subtitle={t('Manage scheduled competitions, entries, scoring windows, and prizes.')}
                action={<Button onClick={() => setCreateOpen(true)}>{t('New tournament')}</Button>}
            />

            <DataTable
                rows={rows}
                columns={columns}
                searchPlaceholder={t('Search tournaments…')}
                initialSearch={filters.search ?? ''}
                rowActions={(row) => (
                    <div className="flex justify-end gap-2">
                        <Button
                            size="sm"
                            variant="ghost"
                            onClick={() => setAwardTarget(row)}
                            title={t('Award prizes')}
                            aria-label={t('Award prizes')}
                        >
                            <Trophy className="size-4" />
                        </Button>
                        <Button
                            size="sm"
                            variant="ghost"
                            onClick={() => setEditTarget(row)}
                            title={t('Edit')}
                            aria-label={t('Edit')}
                        >
                            <Pencil className="size-4" />
                        </Button>
                        <Button
                            size="sm"
                            variant="ghost"
                            onClick={() => setDeleteTarget(row)}
                            title={t('Delete')}
                            aria-label={t('Delete')}
                        >
                            <Trash2 className="size-4 text-destructive" />
                        </Button>
                    </div>
                )}
            />

            <FormDialog
                open={createOpen}
                onOpenChange={setCreateOpen}
                title={t('New tournament')}
                description={t('Create a competition for a playable game.')}
            >
                <TournamentForm games={games} statuses={statuses} onSuccess={() => setCreateOpen(false)} />
            </FormDialog>

            <FormDialog open={!!editTarget} onOpenChange={(open) => !open && setEditTarget(null)} title={t('Edit tournament')}>
                {editTarget && (
                    <TournamentForm
                        initialData={editTarget}
                        games={games}
                        statuses={statuses}
                        onSuccess={() => setEditTarget(null)}
                    />
                )}
            </FormDialog>

            <ConfirmDialog
                open={!!deleteTarget}
                onOpenChange={(open) => !open && setDeleteTarget(null)}
                title={t('Delete tournament?')}
                description={t('Entries and leaderboard rows for this tournament will be removed.')}
                confirmLabel={t('Delete')}
                onConfirm={destroy}
                destructive
            />

            <ConfirmDialog
                open={!!awardTarget}
                onOpenChange={(open) => !open && setAwardTarget(null)}
                title={t('Award prizes for :title?', { title: awardTarget?.title ?? '' })}
                description={t('GP will be granted to the top :n placements (:pool GP pool). This is idempotent — re-running will not double-pay — but the tournament status will be marked completed.', {
                    n: awardTarget?.winner_count ?? 1,
                    pool: formatNumber(awardTarget?.prize_gp ?? 0),
                })}
                confirmLabel={t('Award prizes')}
                onConfirm={awardPrizes}
                destructive={false}
            />
        </DashboardLayout>
    );
}

function TournamentForm({
    initialData,
    games,
    statuses,
    onSuccess,
}: {
    initialData?: TournamentRow;
    games: GameOption[];
    statuses: string[];
    onSuccess: () => void;
}) {
    const { t } = useTranslation();
    const mode = initialData ? 'update' : 'create';
    const { data, setData, post, processing, errors } = useForm<{
        _method: string;
        title: string;
        slug: string;
        description: string;
        image: File | null;
        game_id: string;
        status: string;
        entry_fee_gp: number | '';
        prize_gp: number | '';
        winner_count: number | '';
        prize_distribution: string;
        max_participants: number | '';
        registration_opens_at: string;
        registration_closes_at: string;
        starts_at: string;
        ends_at: string;
        is_active: boolean;
        auto_manage: boolean;
    }>({
        _method: mode === 'update' ? 'put' : 'post',
        title: initialData?.title ?? '',
        slug: initialData?.slug ?? '',
        description: initialData?.description ?? '',
        image: null,
        game_id: String(initialData?.game_id ?? games[0]?.id ?? ''),
        status: initialData?.status ?? 'scheduled',
        entry_fee_gp: initialData?.entry_fee_gp ?? 0,
        prize_gp: initialData?.prize_gp ?? 0,
        winner_count: initialData?.winner_count ?? 1,
        prize_distribution: initialData?.prize_distribution
            ? JSON.stringify(initialData.prize_distribution)
            : '',
        max_participants: initialData?.max_participants ?? '',
        registration_opens_at: initialData?.registration_opens_at?.slice(0, 16) ?? '',
        registration_closes_at: initialData?.registration_closes_at?.slice(0, 16) ?? '',
        starts_at: initialData?.starts_at?.slice(0, 16) ?? '',
        ends_at: initialData?.ends_at?.slice(0, 16) ?? '',
        is_active: initialData?.is_active ?? true,
        auto_manage: initialData?.auto_manage ?? false,
    });

    function submit(e: FormEvent) {
        e.preventDefault();
        post(mode === 'create' ? '/dashboard/tournaments' : `/dashboard/tournaments/${initialData?.id}`, {
            preserveScroll: true,
            forceFormData: true,
            onSuccess,
        });
    }

    const distributionInvalid = (() => {
        if (Number(data.winner_count) <= 1) return false;
        try {
            const dist = JSON.parse(data.prize_distribution || '{}');
            const total = Object.values(dist).reduce<number>(
                (s, v) => s + (typeof v === 'number' ? v : 0),
                0,
            );
            return total !== 100;
        } catch {
            return true;
        }
    })();

    return (
        <form onSubmit={submit} className="space-y-5">
            <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
                <div className="space-y-1.5">
                    <Label htmlFor="t-title">{t('Title')}</Label>
                    <Input
                        id="t-title"
                        value={data.title}
                        onChange={(e) => setData('title', e.target.value)}
                        placeholder={t('e.g. Weekly Score Rush')}
                    />
                    {errors.title && <p className="text-xs text-destructive">{errors.title}</p>}
                </div>
                <div className="space-y-1.5">
                    <Label htmlFor="t-slug">{t('Slug')}</Label>
                    <Input
                        id="t-slug"
                        value={data.slug}
                        onChange={(e) => setData('slug', e.target.value)}
                        placeholder="weekly-score-rush"
                    />
                    <p className="text-xs text-muted-foreground">
                        {t('Leave blank to generate this from the title.')}
                    </p>
                </div>
                <div className="space-y-1.5">
                    <Label htmlFor="t-game">{t('Game')}</Label>
                    <GameCombobox
                        id="t-game"
                        games={games}
                        value={data.game_id}
                        onChange={(value) => setData('game_id', value)}
                    />
                    {games.length === 0 ? (
                        <p className="text-xs text-destructive">
                            {t('No score API enabled games are available.')}
                        </p>
                    ) : (
                        <p className="text-xs text-muted-foreground">
                            {t('Only games with score API enabled can host tournaments.')}
                        </p>
                    )}
                </div>
                <div className="space-y-1.5">
                    <Label htmlFor="t-status">{t('Status')}</Label>
                    <Select value={data.status} onValueChange={(value) => setData('status', value)}>
                        <SelectTrigger id="t-status"><SelectValue placeholder={t('Select status')} /></SelectTrigger>
                        <SelectContent>
                            {statuses.map((status) => <SelectItem key={status} value={status}>{t(labelFor(status))}</SelectItem>)}
                        </SelectContent>
                    </Select>
                    <p className="text-xs text-muted-foreground">
                        {t('Use Active only when scoring should be open.')}
                    </p>
                </div>
                <div className="space-y-1.5 sm:col-span-2">
                    <Label htmlFor="t-description">{t('Description')}</Label>
                    <Textarea
                        id="t-description"
                        value={data.description}
                        onChange={(e) => setData('description', e.target.value)}
                        rows={2}
                        placeholder={t('Rules, prize notes, or event details shown on the tournament page.')}
                    />
                </div>
                <div className="space-y-1.5 sm:col-span-2">
                    <Label htmlFor="t-image">{t('Image')}</Label>
                    <FileInput
                        id="t-image"
                        value={data.image}
                        onChange={(file) => setData('image', file)}
                        buttonLabel={t('Choose image')}
                        replaceLabel={t('Replace image')}
                        emptyHint={t("Leave blank to use the selected game's thumbnail.")}
                        clearable
                        accept="image/jpeg,image/png,image/gif,image/webp"
                    />
                    {initialData?.image && !data.image ? (
                        <div className="mt-1 flex items-center gap-2">
                            <img
                                src={initialData.image.thumbnail ?? initialData.image.standard}
                                alt=""
                                className="h-12 w-20 rounded object-cover"
                            />
                            <span className="text-xs text-muted-foreground">{t('Current image')}</span>
                        </div>
                    ) : (() => {
                        const selectedGame = games.find((game) => String(game.id) === data.game_id);
                        const fallback = selectedGame?.thumbnail?.thumbnail ?? selectedGame?.thumbnail?.standard;
                        if (!data.image && fallback) {
                            return (
                                <div className="mt-1 flex items-center gap-2">
                                    <img
                                        src={fallback}
                                        alt=""
                                        className="h-12 w-20 rounded object-cover opacity-80"
                                    />
                                    <span className="text-xs text-muted-foreground">{t('Using game thumbnail (default)')}</span>
                                </div>
                            );
                        }
                        return null;
                    })()}
                    {errors.image && <p className="text-xs text-destructive">{errors.image}</p>}
                </div>
                <NumberField
                    id="t-entry-fee"
                    label={t('Entry fee (GP)')}
                    value={data.entry_fee_gp}
                    onChange={(value) => setData('entry_fee_gp', value)}
                    placeholder="0"
                    description={t('0 allows free registration. Tournament tickets waive paid entry fees.')}
                />
                <NumberField
                    id="t-prize"
                    label={t('Prize pool (GP)')}
                    value={data.prize_gp}
                    onChange={(value) => setData('prize_gp', value)}
                    placeholder="500"
                    description={t('Total prize pool distributed among winners by percentage.')}
                />
                <NumberField
                    id="t-winner-count"
                    label={t('Number of winners')}
                    value={data.winner_count}
                    onChange={(value) => {
                        setData('winner_count', value);
                        setData('prize_distribution', '');
                    }}
                    placeholder="1"
                    min={1}
                    max={5}
                    description={t('How many top players receive a share of the prize pool.')}
                />
                {Number(data.winner_count) > 1 && (
                    <div className="space-y-2 sm:col-span-2">
                        <Label>{t('Prize distribution (%)')}</Label>
                        <p className="text-xs text-muted-foreground">
                            {t('Set percentage of prize pool for each placement. Must total 100%.')}
                        </p>
                        <div className="grid grid-cols-2 sm:grid-cols-5 gap-2">
                            {Array.from({ length: Number(data.winner_count) }, (_, i) => i + 1).map((rank) => {
                                let currentValue = '';
                                try {
                                    const dist = JSON.parse(data.prize_distribution || '{}');
                                    currentValue = String(dist[String(rank)] ?? '');
                                } catch { /* ignore */ }

                                return (
                                    <div key={rank} className="space-y-1">
                                        <Label className="text-xs">#{rank}</Label>
                                        <Input
                                            type="number"
                                            min={0}
                                            max={100}
                                            placeholder="%"
                                            value={currentValue}
                                            onChange={(e) => {
                                                try {
                                                    const dist = JSON.parse(data.prize_distribution || '{}');
                                                    const v = e.target.value;
                                                    dist[String(rank)] = v === '' ? '' : Number(v);
                                                    setData('prize_distribution', JSON.stringify(dist));
                                                } catch { /* ignore */ }
                                            }}
                                        />
                                    </div>
                                );
                            })}
                        </div>
                        {(() => {
                            try {
                                const dist = JSON.parse(data.prize_distribution || '{}');
                                const total = Object.values(dist).reduce<number>(
                                    (s, v) => s + (typeof v === 'number' ? v : 0),
                                    0,
                                );
                                if (total === 0) return null;
                                const valid = total === 100;
                                return (
                                    <p className={`text-xs ${valid ? 'text-green-600' : 'text-destructive'}`}>
                                        {t('Total: :total%', { total })} {valid ? t('(valid)') : t('(must equal 100%)')}
                                    </p>
                                );
                            } catch {
                                return null;
                            }
                        })()}
                        {errors.prize_distribution && <p className="text-xs text-destructive">{errors.prize_distribution}</p>}
                    </div>
                )}
                <NumberField
                    id="t-max-participants"
                    label={t('Max participants')}
                    value={data.max_participants}
                    onChange={(value) => setData('max_participants', value)}
                    placeholder="100"
                    description={t('Leave blank for unlimited entries.')}
                />
                <DateField
                    id="t-registration-opens"
                    label={t('Registration opens')}
                    value={data.registration_opens_at}
                    onChange={(value) => setData('registration_opens_at', value)}
                    description={t('Leave blank to allow immediate registration.')}
                />
                <DateField
                    id="t-registration-closes"
                    label={t('Registration closes')}
                    value={data.registration_closes_at}
                    onChange={(value) => setData('registration_closes_at', value)}
                    description={t('Leave blank to keep registration open.')}
                />
                <DateField
                    id="t-starts"
                    label={t('Starts')}
                    value={data.starts_at}
                    onChange={(value) => setData('starts_at', value)}
                    description={t('Scores are accepted after this time when status is Active.')}
                />
                <DateField
                    id="t-ends"
                    label={t('Ends')}
                    value={data.ends_at}
                    onChange={(value) => setData('ends_at', value)}
                    description={t('Scores stop being accepted after this time.')}
                />
            </div>
            <div className="flex items-center gap-3 rounded-md border bg-muted/30 p-4">
                <Switch id="t-active" checked={data.is_active} onCheckedChange={(value) => setData('is_active', value)} />
                <div className="space-y-0.5">
                    <Label htmlFor="t-active" className="cursor-pointer">{t('Active')}</Label>
                    <p className="text-xs text-muted-foreground">
                        {t('Inactive tournaments are hidden from public pages.')}
                    </p>
                </div>
            </div>
            <div className="flex items-center gap-3 rounded-md border bg-muted/30 p-4">
                <Switch id="t-auto-manage" checked={data.auto_manage} onCheckedChange={(value) => setData('auto_manage', value)} />
                <div className="space-y-0.5">
                    <Label htmlFor="t-auto-manage" className="cursor-pointer">{t('Auto-manage')}</Label>
                    <p className="text-xs text-muted-foreground">
                        {t('Automatically transitions status (scheduled / active / completed) and awards prizes based on dates.')}
                    </p>
                </div>
            </div>
            <div className="flex justify-end">
                <Button type="submit" disabled={processing || games.length === 0 || !data.game_id || distributionInvalid}>{mode === 'create' ? t('Create tournament') : t('Save changes')}</Button>
            </div>
        </form>
    );
}

function NumberField({
    id,
    label,
    value,
    onChange,
    placeholder,
    description,
    min,
    max,
}: {
    id: string;
    label: string;
    value: number | '';
    onChange: (value: number | '') => void;
    placeholder?: string;
    description?: string;
    min?: number;
    max?: number;
}) {
    return (
        <div className="space-y-1.5">
            <Label htmlFor={id}>{label}</Label>
            <Input
                id={id}
                type="number"
                min={min ?? 0}
                max={max}
                value={value}
                placeholder={placeholder}
                onChange={(e) => onChange(e.target.value === '' ? '' : Number(e.target.value))}
            />
            {description && <p className="text-xs text-muted-foreground">{description}</p>}
        </div>
    );
}

function DateField({
    id,
    label,
    value,
    onChange,
    description,
}: {
    id: string;
    label: string;
    value: string;
    onChange: (value: string) => void;
    description?: string;
}) {
    return (
        <div className="space-y-1.5">
            <Label htmlFor={id}>{label}</Label>
            <DateTimePicker id={id} value={value} onChange={onChange} />
            {description && <p className="text-xs text-muted-foreground">{description}</p>}
        </div>
    );
}

function GameCombobox({
    id,
    games,
    value,
    onChange,
}: {
    id: string;
    games: GameOption[];
    value: string;
    onChange: (value: string) => void;
}) {
    const { t } = useTranslation();
    const [open, setOpen] = useState(false);
    const selected = games.find((game) => String(game.id) === value);

    return (
        <Popover open={open} onOpenChange={setOpen}>
            <PopoverTrigger asChild>
                <Button
                    id={id}
                    type="button"
                    variant="outline"
                    role="combobox"
                    aria-expanded={open}
                    className="w-full justify-between"
                >
                    <span className={cn('truncate', !selected && 'text-muted-foreground')}>
                        {selected ? selected.title : t('Select a score-enabled game')}
                    </span>
                    <ChevronsUpDown className="ms-2 size-4 shrink-0 opacity-50" />
                </Button>
            </PopoverTrigger>
            <PopoverContent className="w-[--radix-popover-trigger-width] p-0" align="start">
                <Command
                    filter={(itemValue, search) => {
                        const haystack = itemValue.toLowerCase();
                        const needle = search.toLowerCase();
                        return haystack.includes(needle) ? 1 : 0;
                    }}
                >
                    <CommandInput placeholder={t('Search games…')} className="h-9" />
                    <CommandList>
                        <CommandEmpty>{t('No score-enabled games match.')}</CommandEmpty>
                        <CommandGroup>
                            {games.map((game) => {
                                const gameId = String(game.id);
                                return (
                                    <CommandItem
                                        key={game.id}
                                        value={`${game.title}__${game.id}`}
                                        className={cn(value === gameId && 'bg-accent font-medium')}
                                        onSelect={() => {
                                            onChange(gameId);
                                            setOpen(false);
                                        }}
                                    >
                                        <Check className={cn('size-4 shrink-0', value === gameId ? 'opacity-100' : 'opacity-0')} />
                                        <span className="truncate">{game.title}</span>
                                    </CommandItem>
                                );
                            })}
                        </CommandGroup>
                    </CommandList>
                </Command>
            </PopoverContent>
        </Popover>
    );
}
