import { router, useForm, Head, usePage } from '@inertiajs/react';
import { useEffect, useRef, useState } from 'react';

import HeadingSmall from '@/components/heading-small';
import HtmlEditor from '@/components/html-editor';
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogHeader,
    DialogTitle,
} from '@/components/ui/dialog';
import AppLayout from '@/layouts/app-layout';
import platformSettings, { index, preview, publish } from '@/routes/admin/platform-settings';
import { discard as discardDraft, save as saveDraft } from '@/routes/admin/platform-settings/draft';

type SettingType = 'html' | 'html_template' | 'text' | 'string' | 'url';

type SettingDefinition = {
    key: string;
    label: string;
    description: string;
    type: SettingType;
    mergeTags: string[];
};

type SettingGroup = {
    group: string;
    settings: SettingDefinition[];
};

type Props = {
    groups: SettingGroup[];
    publishedValues: Record<string, string>;
    draftValues: Record<string, string>;
    hasDraftChanges: boolean;
    lastPublishedAt: string | null;
    lastPublishedBy: string | null;
};

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

function FieldError({ message }: { message?: string }) {
    if (!message) return null;
    return <div className="text-xs text-red-600">{message}</div>;
}

function TestSendDialog({
    open,
    onOpenChange,
}: {
    open: boolean;
    onOpenChange: (open: boolean) => void;
}) {
    const form = useForm<{ email: string }>({ email: '' });

    function handleSubmit(e: React.FormEvent) {
        e.preventDefault();
        form.post(platformSettings.testSend.url(), {
            preserveScroll: true,
            onSuccess: () => {
                onOpenChange(false);
                form.reset();
            },
        });
    }

    return (
        <Dialog open={open} onOpenChange={onOpenChange}>
            <DialogContent>
                <DialogHeader>
                    <DialogTitle>Send a test email</DialogTitle>
                    <DialogDescription>
                        Sends your unpublished draft copy to any address, using the most recent
                        enrollment request as sample data. This does not create a confirmation
                        record or affect production.
                    </DialogDescription>
                </DialogHeader>
                <form onSubmit={handleSubmit} className="flex flex-col gap-3">
                    <div className="flex flex-col gap-1">
                        <label className="text-xs font-medium text-zinc-700 dark:text-zinc-300">
                            Email address
                        </label>
                        <input
                            type="email"
                            value={form.data.email}
                            onChange={(e) => form.setData('email', e.target.value)}
                            className="rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950"
                            autoFocus
                        />
                        <FieldError message={form.errors.email} />
                    </div>
                    <div className="flex justify-end gap-3 pt-2">
                        <button
                            type="button"
                            onClick={() => onOpenChange(false)}
                            className="text-sm text-zinc-600 hover:underline dark:text-zinc-400"
                        >
                            Cancel
                        </button>
                        <button
                            type="submit"
                            disabled={form.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"
                        >
                            Send test email
                        </button>
                    </div>
                </form>
            </DialogContent>
        </Dialog>
    );
}

function PreviewDialog({ open, onOpenChange }: { open: boolean; onOpenChange: (open: boolean) => void }) {
    const [html, setHtml] = useState<string | null>(null);

    useEffect(() => {
        if (!open) {
            return;
        }

        let cancelled = false;
        fetch(preview.url(), { credentials: 'same-origin' })
            .then((response) => response.text())
            .then((body) => {
                if (!cancelled) {
                    setHtml(body);
                }
            });

        return () => {
            cancelled = true;
            setHtml(null);
        };
    }, [open]);

    return (
        <Dialog open={open} onOpenChange={onOpenChange}>
            <DialogContent className="max-w-3xl">
                <DialogHeader>
                    <DialogTitle>Preview (draft copy)</DialogTitle>
                    <DialogDescription>
                        Rendered using the most recent enrollment request as sample data.
                    </DialogDescription>
                </DialogHeader>
                {open && html !== null && (
                    <iframe
                        srcDoc={html}
                        title="Enrollment confirmation preview"
                        className="h-[70vh] w-full rounded-md border border-zinc-200 dark:border-zinc-800"
                    />
                )}
            </DialogContent>
        </Dialog>
    );
}

export default function PlatformSettings({
    groups,
    draftValues,
    hasDraftChanges,
    lastPublishedAt,
    lastPublishedBy,
}: Props) {
    const {
        props: { flash },
    } = usePage<{ flash: { success?: string } }>();
    const [testSendOpen, setTestSendOpen] = useState(false);
    const [previewOpen, setPreviewOpen] = useState(false);
    const [publishing, setPublishing] = useState(false);
    const [discarding, setDiscarding] = useState(false);

    const form = useForm<{ settings: Record<string, string> }>({ settings: draftValues });
    const errors = form.errors as Record<string, string>;
    const fieldRefs = useRef<Record<string, HTMLTextAreaElement | HTMLInputElement | null>>({});

    function updateSetting(key: string, value: string) {
        form.setData((data) => ({ settings: { ...data.settings, [key]: value } }));
    }

    function insertMergeTag(key: string, tag: string) {
        const tagText = `{{${tag}}}`;
        const current = form.data.settings[key] ?? '';
        const el = fieldRefs.current[key];

        if (!el || el.selectionStart === null) {
            updateSetting(key, current + tagText);
            return;
        }

        const start = el.selectionStart;
        const end = el.selectionEnd ?? start;
        updateSetting(key, current.slice(0, start) + tagText + current.slice(end));

        requestAnimationFrame(() => {
            const cursor = start + tagText.length;
            el.focus();
            el.setSelectionRange(cursor, cursor);
        });
    }

    function handleSaveDraft(e: React.FormEvent) {
        e.preventDefault();
        form.put(saveDraft.url(), { preserveScroll: true });
    }

    function handlePublish() {
        setPublishing(true);
        router.post(
            publish.url(),
            {},
            { preserveScroll: true, onFinish: () => setPublishing(false) },
        );
    }

    function handleDiscard() {
        setDiscarding(true);
        router.delete(discardDraft.url(), {
            preserveScroll: true,
            onFinish: () => setDiscarding(false),
        });
    }

    const inputClass =
        'rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm dark:border-zinc-800 dark:bg-zinc-950';
    const labelClass = 'text-xs font-medium text-zinc-700 dark:text-zinc-300';

    return (
        <AppLayout breadcrumbs={breadcrumbs}>
            <Head title="Platform Settings" />

            <h1 className="sr-only">Platform Settings</h1>

            <div className="space-y-6">
                <div className="flex flex-wrap items-start justify-between gap-4">
                    <HeadingSmall
                        title="Platform Settings"
                        description="Copy and configuration that can change in production without a deploy."
                    />
                    <div className="flex items-center gap-2">
                        <button
                            type="button"
                            onClick={() => setTestSendOpen(true)}
                            className="rounded-md border border-zinc-200 px-3 py-2 text-sm dark:border-zinc-800"
                        >
                            Send test email
                        </button>
                        <button
                            type="button"
                            onClick={() => setPreviewOpen(true)}
                            className="rounded-md border border-zinc-200 px-3 py-2 text-sm dark:border-zinc-800"
                        >
                            Preview
                        </button>
                        <button
                            type="button"
                            onClick={handleDiscard}
                            disabled={!hasDraftChanges || discarding}
                            className="rounded-md border border-zinc-200 px-3 py-2 text-sm disabled:opacity-40 dark:border-zinc-800"
                        >
                            Discard draft
                        </button>
                        <button
                            type="button"
                            onClick={handlePublish}
                            disabled={!hasDraftChanges || publishing}
                            className="rounded-md bg-emerald-600 px-3 py-2 text-sm font-medium text-white disabled:opacity-40"
                        >
                            Publish
                        </button>
                    </div>
                </div>

                {flash?.success && (
                    <div className="rounded-md border border-emerald-200 bg-emerald-50 px-4 py-2 text-sm text-emerald-800 dark:border-emerald-900 dark:bg-emerald-950 dark:text-emerald-200">
                        {flash.success}
                    </div>
                )}

                {hasDraftChanges && (
                    <div className="rounded-md border border-amber-300 bg-amber-50 px-4 py-3 text-sm text-amber-800 dark:border-amber-800 dark:bg-amber-950 dark:text-amber-200">
                        You have unpublished changes. Send a test email to check them, then Publish
                        to make them live.
                    </div>
                )}

                <form onSubmit={handleSaveDraft} className="space-y-8">
                    {groups.map((group) => (
                        <div key={group.group} className="space-y-4">
                            <h2 className="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
                                {group.group}
                            </h2>
                            <div className="space-y-6 rounded-lg border border-zinc-200 p-4 dark:border-zinc-800">
                                {group.settings.map((setting) => (
                                    <div key={setting.key} className="flex flex-col gap-1">
                                        <label className={labelClass}>{setting.label}</label>
                                        <p className="text-xs text-zinc-500 dark:text-zinc-400">
                                            {setting.description}
                                        </p>

                                        {setting.type === 'html' && (
                                            <HtmlEditor
                                                value={form.data.settings[setting.key] ?? ''}
                                                onChange={(html) => updateSetting(setting.key, html)}
                                                allowSourceEditing
                                            />
                                        )}
                                        {setting.type === 'html_template' && (
                                            <textarea
                                                ref={(el) => {
                                                    fieldRefs.current[setting.key] = el;
                                                }}
                                                value={form.data.settings[setting.key] ?? ''}
                                                onChange={(e) =>
                                                    updateSetting(setting.key, e.target.value)
                                                }
                                                rows={24}
                                                spellCheck={false}
                                                className={`${inputClass} font-mono text-xs`}
                                            />
                                        )}
                                        {setting.type === 'text' && (
                                            <textarea
                                                ref={(el) => {
                                                    fieldRefs.current[setting.key] = el;
                                                }}
                                                value={form.data.settings[setting.key] ?? ''}
                                                onChange={(e) =>
                                                    updateSetting(setting.key, e.target.value)
                                                }
                                                rows={3}
                                                className={inputClass}
                                            />
                                        )}
                                        {(setting.type === 'string' || setting.type === 'url') && (
                                            <input
                                                ref={(el) => {
                                                    fieldRefs.current[setting.key] = el;
                                                }}
                                                type={setting.type === 'url' ? 'url' : 'text'}
                                                value={form.data.settings[setting.key] ?? ''}
                                                onChange={(e) =>
                                                    updateSetting(setting.key, e.target.value)
                                                }
                                                className={inputClass}
                                            />
                                        )}

                                        <FieldError message={errors[`settings.${setting.key}`]} />

                                        {setting.mergeTags.length > 0 && (
                                            <div className="flex flex-wrap gap-1 pt-1">
                                                {setting.mergeTags.map((tag) => (
                                                    <button
                                                        key={tag}
                                                        type="button"
                                                        onClick={() => insertMergeTag(setting.key, tag)}
                                                        className="rounded border border-zinc-200 px-1.5 py-0.5 font-mono text-[11px] text-zinc-500 hover:bg-zinc-100 dark:border-zinc-700 dark:text-zinc-400 dark:hover:bg-zinc-800"
                                                    >
                                                        {`{{${tag}}}`}
                                                    </button>
                                                ))}
                                            </div>
                                        )}
                                    </div>
                                ))}
                            </div>
                        </div>
                    ))}

                    <div className="flex items-center gap-3">
                        <button
                            type="submit"
                            disabled={form.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 draft
                        </button>
                        {form.recentlySuccessful && (
                            <span className="text-xs text-emerald-600">Draft saved.</span>
                        )}
                    </div>
                </form>

                <p className="text-xs text-zinc-500 dark:text-zinc-400">
                    {lastPublishedAt
                        ? `Last published ${new Date(lastPublishedAt).toLocaleString()}${lastPublishedBy ? ` by ${lastPublishedBy}` : ''}.`
                        : 'Never published — production is using the built-in defaults.'}
                </p>
            </div>

            <TestSendDialog open={testSendOpen} onOpenChange={setTestSendOpen} />
            <PreviewDialog open={previewOpen} onOpenChange={setPreviewOpen} />
        </AppLayout>
    );
}
