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

import { CheckboxCard } from '@/components/ui/checkbox-card';
import { Switch } from '@/components/ui/switch';
import { AdminLayout } from '@/layouts/admin-layout';

type AbilityOption = {
    value: string;
    label: string;
};

type ApiTokenForm = {
    name: string;
    abilities: string[];
    is_active: boolean;
    expires_at: string;
};

type ApiTokenCreateProps = {
    abilityOptions: AbilityOption[];
};

export default function ApiTokenCreate({
    abilityOptions,
}: ApiTokenCreateProps) {
    const form = useForm<ApiTokenForm>({
        name: '',
        abilities: [],
        is_active: true,
        expires_at: '',
    });

    const submit = (event: React.FormEvent<HTMLFormElement>) => {
        event.preventDefault();

        form.transform((data) => ({
            ...data,
            expires_at: data.expires_at === '' ? null : data.expires_at,
        }));

        form.post('/admin/api-tokens');
    };

    return (
        <AdminLayout>
            <Head title="Create API Token" />
            <ApiTokenFormView
                title="Create API Token"
                form={form}
                abilityOptions={abilityOptions}
                onSubmit={submit}
                submitLabel="Create Token"
            />
        </AdminLayout>
    );
}

type FormViewProps = {
    title: string;
    form: ReturnType<typeof useForm<ApiTokenForm>>;
    abilityOptions: AbilityOption[];
    onSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
    submitLabel: string;
};

export function ApiTokenFormView({
    title,
    form,
    abilityOptions,
    onSubmit,
    submitLabel,
}: FormViewProps) {
    const allAbilityValues = abilityOptions.map((option) => option.value);
    const granularAbilityValues = allAbilityValues.filter(
        (ability) => ability !== '*',
    );
    const allGranularSelected = granularAbilityValues.every((ability) =>
        form.data.abilities.includes(ability),
    );
    const fullAccessSelected =
        form.data.abilities.includes('*') && allGranularSelected;

    const toggleAbility = (ability: string) => {
        if (ability === '*') {
            form.setData(
                'abilities',
                fullAccessSelected ? [] : allAbilityValues,
            );

            return;
        }

        const nextAbilities = form.data.abilities.includes(ability)
            ? form.data.abilities.filter(
                  (item) => item !== ability && item !== '*',
              )
            : [...form.data.abilities, ability];

        const uniqueAbilities = Array.from(new Set(nextAbilities));

        form.setData(
            'abilities',
            granularAbilityValues.every((item) =>
                uniqueAbilities.includes(item),
            )
                ? Array.from(new Set(['*', ...uniqueAbilities]))
                : uniqueAbilities,
        );
    };

    const selectAllAbilities = () => {
        form.setData('abilities', allAbilityValues);
    };

    const clearAbilities = () => {
        form.setData('abilities', []);
    };

    return (
        <div className="space-y-5">
            <div className="flex flex-wrap items-center justify-between gap-3">
                <div>
                    <h1 className="text-2xl font-semibold text-[#0a1530] dark:text-[#efe8ff]">
                        {title}
                    </h1>
                    <p className="mt-1 text-sm text-slate-600 dark:text-[#c7bde8]">
                        Tokens are shown once after creation and stored only as
                        hashes.
                    </p>
                </div>
                <Link
                    href="/admin/api-tokens"
                    className="text-sm font-medium text-slate-600 hover:text-[#0a1530] dark:text-[#d7c7ff] dark:hover:text-[#efe8ff]"
                >
                    Back to tokens
                </Link>
            </div>

            <form onSubmit={onSubmit} className="space-y-5">
                <div className="grid gap-4 md:grid-cols-2">
                    <Field label="Token Name" error={form.errors.name}>
                        <input
                            value={form.data.name}
                            onChange={(event) =>
                                form.setData('name', event.target.value)
                            }
                            required
                            placeholder="ERP catalog sync"
                            className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                        />
                    </Field>
                    <Field
                        label="Expires At"
                        error={form.errors.expires_at}
                        help="Optional. Leave blank for no expiration."
                    >
                        <input
                            type="datetime-local"
                            value={form.data.expires_at}
                            onChange={(event) =>
                                form.setData('expires_at', event.target.value)
                            }
                            className="w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-[#0a1530] outline-none focus:border-[#0b7285] dark:border-[#4a3a78] dark:bg-[#160f2d] dark:text-[#efe8ff] dark:focus:border-[#a78bfa]"
                        />
                    </Field>
                </div>

                <div className="rounded-xl border border-slate-200 p-4 dark:border-[#3c2b68]">
                    <div className="flex items-center gap-3">
                        <Switch
                            checked={form.data.is_active}
                            onChange={(checked) =>
                                form.setData('is_active', checked)
                            }
                            ariaLabel="Toggle API token active state"
                        />
                        <span className="text-sm font-medium text-[#0a1530] dark:text-[#e5dcff]">
                            Active token
                        </span>
                    </div>
                </div>

                <Field label="Abilities" error={form.errors.abilities}>
                    <div className="mb-3 flex flex-wrap gap-2">
                        <button
                            type="button"
                            onClick={selectAllAbilities}
                            className="rounded-lg border border-slate-300 px-3 py-1.5 text-xs font-semibold text-[#0a1530] hover:border-[#0b7285] hover:text-[#0b7285] dark:border-[#4a3a78] dark:text-[#e5dcff] dark:hover:border-[#a78bfa]"
                        >
                            Select all
                        </button>
                        <button
                            type="button"
                            onClick={clearAbilities}
                            className="rounded-lg border border-slate-300 px-3 py-1.5 text-xs font-semibold text-slate-600 hover:border-rose-300 hover:text-rose-600 dark:border-[#4a3a78] dark:text-[#c7bde8] dark:hover:border-rose-400"
                        >
                            Clear
                        </button>
                    </div>
                    <div className="grid gap-2 md:grid-cols-2 xl:grid-cols-3">
                        {abilityOptions.map((option) => (
                            <CheckboxCard
                                key={option.value}
                                checked={form.data.abilities.includes(
                                    option.value,
                                )}
                                onChange={() => toggleAbility(option.value)}
                                label={option.label}
                            />
                        ))}
                    </div>
                </Field>

                <button
                    type="submit"
                    disabled={form.processing}
                    className="rounded-lg bg-[#0b7285] px-4 py-2 text-sm font-semibold text-white hover:bg-[#095f6f] disabled:opacity-50 dark:bg-[#7c3aed] dark:hover:bg-[#8b5cf6]"
                >
                    {form.processing ? 'Saving...' : submitLabel}
                </button>
            </form>
        </div>
    );
}

function Field({
    label,
    error,
    help,
    children,
}: {
    label: string;
    error?: string;
    help?: string;
    children: React.ReactNode;
}) {
    return (
        <div>
            <label className="block text-sm font-medium text-[#0a1530] dark:text-[#e5dcff]">
                {label}
            </label>
            <div className="mt-1">{children}</div>
            {help ? (
                <p className="mt-1 text-xs text-slate-500 dark:text-[#bcaee6]">
                    {help}
                </p>
            ) : null}
            {error ? (
                <p className="mt-1 text-xs text-rose-600">{error}</p>
            ) : null}
        </div>
    );
}
