import { Form, Head } from '@inertiajs/react';
import { useRef, useState } from 'react';

import HeadingSmall from '@/components/heading-small';
import { SortableHeader, useSort } from '@/components/sortable-header';
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogHeader,
    DialogTitle,
    DialogTrigger,
} from '@/components/ui/dialog';
import AppLayout from '@/layouts/app-layout';
import { destroy, index, store, update } from '@/routes/admin/form-fields';

type FormField = {
    id: number;
    name: string;
    label: string;
    type: string;
    options: string[] | null;
    required: boolean;
    placeholder: string | null;
    validation_pattern: string | null;
    validation_message: string | null;
    help_text: string | null;
};

type Props = {
    formFields: FormField[];
    fieldTypes: string[];
};

function highlightJson(text: string): string {
    const escaped = text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    return escaped.replace(
        /("(?:\\u[a-fA-F0-9]{4}|\\[^u]|[^\\"])*"(?:\s*:)?|\b(?:true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g,
        (match) => {
            let variable: string;
            if (match.startsWith('"')) {
                variable = match.trimEnd().endsWith(':') ? '--json-key' : '--json-string';
            } else if (match === 'true' || match === 'false') {
                variable = '--json-boolean';
            } else if (match === 'null') {
                variable = '--json-null';
            } else {
                variable = '--json-number';
            }
            return `<span style="color:var(${variable})">${match}</span>`;
        },
    );
}

function JsonEditor({ name, defaultValue = '' }: { name: string; defaultValue?: string }) {
    const [value, setValue] = useState(() => {
        if (!defaultValue) return defaultValue;
        try {
            return JSON.stringify(JSON.parse(defaultValue), null, 2);
        } catch {
            return defaultValue;
        }
    });

    const preRef = useRef<HTMLPreElement>(null);
    const textareaRef = useRef<HTMLTextAreaElement>(null);

    let isValid = true;
    if (value.trim()) {
        try {
            JSON.parse(value);
        } catch {
            isValid = false;
        }
    }

    function syncScroll() {
        if (preRef.current && textareaRef.current) {
            preRef.current.scrollTop = textareaRef.current.scrollTop;
        }
    }

    const sharedClass = 'font-mono text-xs leading-5 p-3 whitespace-pre-wrap break-all';
    const borderClass = isValid
        ? 'border-zinc-300 dark:border-zinc-700'
        : 'border-red-500 dark:border-red-500';

    return (
        <div
            className={`relative isolate rounded-md border ${borderClass} focus-within:ring-2 focus-within:ring-zinc-400 dark:focus-within:ring-zinc-500 focus-within:ring-offset-0`}
        >
            <pre
                ref={preRef}
                aria-hidden
                tabIndex={-1}
                style={{ backgroundColor: 'var(--json-editor-bg)' }}
                className={`pointer-events-none absolute inset-0 overflow-hidden rounded-md text-zinc-800 dark:text-zinc-200 ${sharedClass}`}
                dangerouslySetInnerHTML={{ __html: highlightJson(value) + ' ' }}
            />
            <textarea
                ref={textareaRef}
                name={name}
                value={value}
                onChange={(e) => setValue(e.target.value)}
                onScroll={syncScroll}
                rows={12}
                spellCheck={false}
                autoComplete="off"
                className={`relative w-full resize-y rounded-md bg-transparent text-transparent caret-zinc-900 dark:caret-white focus:outline-none ${sharedClass}`}
            />
        </div>
    );
}

const breadcrumbs = [{ title: 'Form Fields', href: index.url() }];

export default function FormFields({ formFields, fieldTypes }: Props) {
    const [createOpen, setCreateOpen] = useState(false);
    const [editingId, setEditingId] = useState<number | null>(null);
    const { sorted, sortColumn, sortDirection, toggleSort } = useSort<FormField>(formFields, 'name');

    return (
        <AppLayout breadcrumbs={breadcrumbs}>
            <Head title="Form Fields" />

            <h1 className="sr-only">Form Fields</h1>

            <div className="space-y-6">
                <div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
                    <HeadingSmall
                        title="Form Fields"
                        description="Manage the form fields available for web forms."
                    />

                    <Dialog open={createOpen} onOpenChange={setCreateOpen}>
                        <DialogTrigger asChild>
                            <button
                                type="button"
                                className="rounded-md bg-zinc-900 px-3 py-2 text-sm font-medium text-white dark:bg-zinc-100 dark:text-zinc-900"
                            >
                                Add form field
                            </button>
                        </DialogTrigger>

                        <DialogContent className="sm:max-w-2xl">
                            <DialogHeader>
                                <DialogTitle>Add form field</DialogTitle>
                                <DialogDescription>
                                    Create a new form field for web forms.
                                </DialogDescription>
                            </DialogHeader>

                            <Form
                                method="post"
                                action={store.url()}
                                resetOnSuccess
                                onSuccess={() => setCreateOpen(false)}
                            >
                                {({ processing, errors }) => (
                                    <div className="grid grid-cols-1 gap-3 sm:grid-cols-6">
                                        <div className="flex flex-col gap-1 sm:col-span-2">
                                            <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                Name
                                            </label>
                                            <input
                                                name="name"
                                                className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                placeholder="first_name"
                                            />
                                            {errors.name && (
                                                <div className="text-xs text-red-600">{errors.name}</div>
                                            )}
                                        </div>

                                        <div className="flex flex-col gap-1 sm:col-span-2">
                                            <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                Label
                                            </label>
                                            <input
                                                name="label"
                                                className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                placeholder="First Name"
                                            />
                                            {errors.label && (
                                                <div className="text-xs text-red-600">{errors.label}</div>
                                            )}
                                        </div>

                                        <div className="flex flex-col gap-1">
                                            <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                Type
                                            </label>
                                            <select
                                                name="type"
                                                className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                defaultValue=""
                                            >
                                                <option value="" disabled>
                                                    Select...
                                                </option>
                                                {fieldTypes.map((t) => (
                                                    <option key={t} value={t}>
                                                        {t}
                                                    </option>
                                                ))}
                                            </select>
                                            {errors.type && (
                                                <div className="text-xs text-red-600">{errors.type}</div>
                                            )}
                                        </div>

                                        <div className="flex flex-col gap-1">
                                            <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                Required
                                            </label>
                                            <select
                                                name="required"
                                                className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                defaultValue="0"
                                            >
                                                <option value="0">No</option>
                                                <option value="1">Yes</option>
                                            </select>
                                        </div>

                                        <div className="flex flex-col gap-1 sm:col-span-2">
                                            <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                Placeholder
                                            </label>
                                            <input
                                                name="placeholder"
                                                className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                placeholder="Enter value..."
                                            />
                                        </div>

                                        <div className="flex flex-col gap-1 sm:col-span-2">
                                            <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                Validation Pattern
                                            </label>
                                            <input
                                                name="validation_pattern"
                                                className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                placeholder="^[A-Z]{2}$"
                                            />
                                        </div>

                                        <div className="flex flex-col gap-1 sm:col-span-2">
                                            <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                Validation Message
                                            </label>
                                            <textarea
                                                name="validation_message"
                                                rows={2}
                                                className="resize-y rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                placeholder="Please enter a valid value."
                                            />
                                        </div>

                                        <div className="flex flex-col gap-1 sm:col-span-6">
                                            <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                Help Text
                                            </label>
                                            <textarea
                                                name="help_text"
                                                rows={3}
                                                className="resize-y rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                placeholder="Helpful description shown beneath the field"
                                            />
                                        </div>

                                        <div className="flex flex-col gap-1 sm:col-span-6">
                                            <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                Options
                                                <span className="ml-1 font-normal text-zinc-500 dark:text-zinc-400">
                                                    — JSON array or named list (e.g. US_STATES)
                                                </span>
                                            </label>
                                            <JsonEditor name="options" />
                                            {errors.options && (
                                                <div className="text-xs text-red-600">{errors.options}</div>
                                            )}
                                        </div>

                                        <div className="flex items-end justify-end gap-3 sm:col-span-6">
                                            <button
                                                type="button"
                                                onClick={() => setCreateOpen(false)}
                                                className="rounded-md px-3 py-2 text-sm font-medium text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
                                            >
                                                Cancel
                                            </button>
                                            <button
                                                type="submit"
                                                disabled={processing}
                                                className="rounded-md bg-zinc-900 px-3 py-2 text-sm font-medium text-white disabled:opacity-60 dark:bg-zinc-100 dark:text-zinc-900"
                                            >
                                                Add form field
                                            </button>
                                        </div>
                                    </div>
                                )}
                            </Form>
                        </DialogContent>
                    </Dialog>
                </div>

                {/* Form fields table */}
                <div className="overflow-hidden rounded-md border border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-950">
                    <div className="overflow-x-auto">
                        <table className="w-full text-left text-sm">
                            <thead className="border-b border-zinc-200 text-xs uppercase text-zinc-600 dark:border-zinc-800 dark:text-zinc-400">
                                <tr>
                                    <SortableHeader label="Name" column="name" sortColumn={sortColumn} sortDirection={sortDirection} onSort={toggleSort} />
                                    <SortableHeader label="Label" column="label" sortColumn={sortColumn} sortDirection={sortDirection} onSort={toggleSort} />
                                    <SortableHeader label="Type" column="type" sortColumn={sortColumn} sortDirection={sortDirection} onSort={toggleSort} />
                                    <SortableHeader label="Required" column="required" sortColumn={sortColumn} sortDirection={sortDirection} onSort={toggleSort} />
                                    <th className="px-4 py-3">Options</th>
                                    <th className="px-4 py-3" />
                                </tr>
                            </thead>
                            <tbody className="divide-y divide-zinc-200 dark:divide-zinc-800">
                                {sorted.map((f) => (
                                    <tr key={f.id}>
                                        <td className="px-4 py-3 font-mono text-xs font-medium">
                                            {f.name}
                                        </td>
                                        <td className="px-4 py-3">{f.label}</td>
                                        <td className="px-4 py-3 text-zinc-600 dark:text-zinc-400">
                                            {f.type}
                                        </td>
                                        <td className="px-4 py-3 text-zinc-600 dark:text-zinc-400">
                                            {f.required ? 'Yes' : 'No'}
                                        </td>
                                        <td className="px-4 py-3 font-mono text-xs text-zinc-600 dark:text-zinc-400">
                                            {f.options ? JSON.stringify(f.options) : '\u2014'}
                                        </td>
                                        <td className="px-4 py-3 text-right">
                                            <div className="flex items-center justify-end gap-4">
                                                <Dialog
                                                    open={editingId === f.id}
                                                    onOpenChange={(open) => setEditingId(open ? f.id : null)}
                                                >
                                                    <DialogTrigger asChild>
                                                        <button
                                                            type="button"
                                                            className="text-sm text-zinc-700 hover:underline dark:text-zinc-300"
                                                        >
                                                            Edit
                                                        </button>
                                                    </DialogTrigger>

                                                    <DialogContent className="sm:max-w-2xl">
                                                        <DialogHeader>
                                                            <DialogTitle>Edit form field</DialogTitle>
                                                            <DialogDescription>
                                                                Update {f.name} settings.
                                                            </DialogDescription>
                                                        </DialogHeader>

                                                        <Form
                                                            method="put"
                                                            action={update.url(f.id)}
                                                            onSuccess={() => setEditingId(null)}
                                                        >
                                                            {({ processing, errors }) => (
                                                                <div className="grid grid-cols-1 gap-3 sm:grid-cols-6">
                                                                    <div className="flex flex-col gap-1 sm:col-span-2">
                                                                        <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                                            Name
                                                                        </label>
                                                                        <input
                                                                            name="name"
                                                                            defaultValue={f.name}
                                                                            className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                                        />
                                                                        {errors.name && (
                                                                            <div className="text-xs text-red-600">
                                                                                {errors.name}
                                                                            </div>
                                                                        )}
                                                                    </div>

                                                                    <div className="flex flex-col gap-1 sm:col-span-2">
                                                                        <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                                            Label
                                                                        </label>
                                                                        <input
                                                                            name="label"
                                                                            defaultValue={f.label}
                                                                            className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                                        />
                                                                        {errors.label && (
                                                                            <div className="text-xs text-red-600">
                                                                                {errors.label}
                                                                            </div>
                                                                        )}
                                                                    </div>

                                                                    <div className="flex flex-col gap-1">
                                                                        <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                                            Type
                                                                        </label>
                                                                        <select
                                                                            name="type"
                                                                            defaultValue={f.type}
                                                                            className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                                        >
                                                                            {fieldTypes.map((t) => (
                                                                                <option key={t} value={t}>
                                                                                    {t}
                                                                                </option>
                                                                            ))}
                                                                        </select>
                                                                        {errors.type && (
                                                                            <div className="text-xs text-red-600">
                                                                                {errors.type}
                                                                            </div>
                                                                        )}
                                                                    </div>

                                                                    <div className="flex flex-col gap-1">
                                                                        <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                                            Required
                                                                        </label>
                                                                        <select
                                                                            name="required"
                                                                            defaultValue={f.required ? '1' : '0'}
                                                                            className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                                        >
                                                                            <option value="0">No</option>
                                                                            <option value="1">Yes</option>
                                                                        </select>
                                                                    </div>

                                                                    <div className="flex flex-col gap-1 sm:col-span-2">
                                                                        <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                                            Placeholder
                                                                        </label>
                                                                        <input
                                                                            name="placeholder"
                                                                            defaultValue={f.placeholder ?? ''}
                                                                            className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                                        />
                                                                    </div>

                                                                    <div className="flex flex-col gap-1 sm:col-span-2">
                                                                        <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                                            Validation Pattern
                                                                        </label>
                                                                        <input
                                                                            name="validation_pattern"
                                                                            defaultValue={f.validation_pattern ?? ''}
                                                                            className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                                        />
                                                                    </div>

                                                                    <div className="flex flex-col gap-1 sm:col-span-2">
                                                                        <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                                            Validation Message
                                                                        </label>
                                                                        <textarea
                                                                            name="validation_message"
                                                                            defaultValue={f.validation_message ?? ''}
                                                                            rows={2}
                                                                            className="resize-y rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                                        />
                                                                    </div>

                                                                    <div className="flex flex-col gap-1 sm:col-span-6">
                                                                        <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                                            Help Text
                                                                        </label>
                                                                        <textarea
                                                                            name="help_text"
                                                                            defaultValue={f.help_text ?? ''}
                                                                            rows={3}
                                                                            className="resize-y rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                                                                        />
                                                                    </div>

                                                                    <div className="flex flex-col gap-1 sm:col-span-6">
                                                                        <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                                                                            Options
                                                                            <span className="ml-1 font-normal text-zinc-500 dark:text-zinc-400">
                                                                                — JSON array or named list (e.g. US_STATES)
                                                                            </span>
                                                                        </label>
                                                                        <JsonEditor
                                                                            name="options"
                                                                            defaultValue={
                                                                                f.options
                                                                                    ? Array.isArray(f.options)
                                                                                        ? JSON.stringify(f.options)
                                                                                        : f.options
                                                                                    : ''
                                                                            }
                                                                        />
                                                                        {errors.options && (
                                                                            <div className="text-xs text-red-600">
                                                                                {errors.options}
                                                                            </div>
                                                                        )}
                                                                    </div>

                                                                    <div className="flex items-end justify-end gap-3 sm:col-span-6">
                                                                        <button
                                                                            type="button"
                                                                            onClick={() => setEditingId(null)}
                                                                            className="rounded-md px-3 py-2 text-sm font-medium text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-100"
                                                                        >
                                                                            Cancel
                                                                        </button>
                                                                        <button
                                                                            type="submit"
                                                                            disabled={processing}
                                                                            className="rounded-md bg-zinc-900 px-3 py-2 text-sm font-medium text-white disabled:opacity-60 dark:bg-zinc-100 dark:text-zinc-900"
                                                                        >
                                                                            Save
                                                                        </button>
                                                                    </div>
                                                                </div>
                                                            )}
                                                        </Form>
                                                    </DialogContent>
                                                </Dialog>

                                                <Form method="delete" action={destroy.url(f.id)}>
                                                    {({ processing }) => (
                                                        <button
                                                            type="submit"
                                                            disabled={processing}
                                                            className="text-sm text-red-700 hover:underline disabled:opacity-60 dark:text-red-400"
                                                        >
                                                            Delete
                                                        </button>
                                                    )}
                                                </Form>
                                            </div>
                                        </td>
                                    </tr>
                                ))}
                            </tbody>
                        </table>
                    </div>

                    {formFields.length === 0 && (
                        <div className="p-4 text-sm text-zinc-600 dark:text-zinc-400">
                            No form fields yet.
                        </div>
                    )}
                </div>
            </div>
        </AppLayout>
    );
}
