import { Head } from '@inertiajs/react';
import { useCallback, useEffect, useState } from 'react';

import HeadingSmall from '@/components/heading-small';
import AppLayout from '@/layouts/app-layout';
import { productProperName } from '@/lib/utils';
import { index } from '@/routes/admin/enrollment-test';

type Supplier = { id: number; name: string; slug: string };
type WebFormOption = { id: number; slug: string; name: string };
type SupplierState = { id: number; name: string; code: string };
type SampleZip = { zipcode: string; place_name: string };
type SupplierUtility = { id: number; name: string; state_id: number; sample_zips: SampleZip[] };
type SupplierProduct = { id: number; name: string; utility_id: number };
type SupplierData = {
    states: SupplierState[];
    utilities: SupplierUtility[];
    products: SupplierProduct[];
};
type FormField = {
    name: string;
    label: string;
    type: string;
    options: { value: string; label: string }[] | null;
    required: boolean;
    placeholder: string | null;
    validation_pattern: string | null;
    validation_message: string | null;
    help_text: string | null;
    display_order: number;
    value?: string;
};
type WebFormSection = {
    name: string | null;
    label: string | null;
    description: string | null;
    display_order: number;
    fields: FormField[];
};
type WebFormData = {
    id: number;
    slug: string;
    name: string;
    description: string | null;
    sections: WebFormSection[];
};

type Props = {
    suppliers: Supplier[];
    webForms: WebFormOption[];
};

const FIRST_NAMES = ['Jane', 'John', 'Sarah', 'Michael', 'Emily', 'David', 'Emma', 'Robert'];
const LAST_NAMES = ['Smith', 'Johnson', 'Williams', 'Brown', 'Jones', 'Garcia', 'Miller', 'Davis'];
const STREETS = ['Main St', 'Oak Ave', 'Elm St', 'Maple Dr', 'Cedar Ln'];

function randomItem<T>(arr: T[]): T {
    return arr[Math.floor(Math.random() * arr.length)];
}

function randomInt(min: number, max: number): number {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function randomDigits(count: number): string {
    return Array.from({ length: count }, () => String(randomInt(0, 9))).join('');
}

function parseQuantifier(pattern: string, i: number): { count: number; newIndex: number } {
    if (i >= pattern.length || pattern[i] !== '{') {
        return { count: 1, newIndex: i };
    }
    const end = pattern.indexOf('}', i);
    if (end === -1) return { count: 1, newIndex: i };
    const quantifier = pattern.slice(i + 1, end);
    let count: number;
    if (quantifier.includes(',')) {
        const [minStr, maxStr] = quantifier.split(',');
        const min = parseInt(minStr, 10);
        const max = maxStr.trim() === '' ? min + 3 : parseInt(maxStr, 10);
        count = randomInt(min, max);
    } else {
        count = parseInt(quantifier, 10);
    }
    return { count, newIndex: end + 1 };
}

/**
 * Generates a sample string that satisfies simple structural regex patterns of the kind
 * used for utility account identifiers: literal chars, \d{n}, [0-9]{n}, and (alt1|alt2).
 */
function generateFromRegex(pattern: string): string {
    const p = pattern.replace(/^\^/, '').replace(/\$$/, '');
    let result = '';
    let i = 0;

    while (i < p.length) {
        if (p[i] === '(') {
            const end = p.indexOf(')', i);
            if (end === -1) { result += p[i++]; continue; }
            const firstAlt = p.slice(i + 1, end).split('|')[0];
            result += firstAlt;
            i = end + 1;
        } else if (p[i] === '\\' && p[i + 1] === 'd') {
            i += 2;
            const { count, newIndex } = parseQuantifier(p, i);
            i = newIndex;
            result += randomDigits(count);
        } else if (p[i] === '[') {
            const end = p.indexOf(']', i);
            if (end === -1) { result += p[i++]; continue; }
            i = end + 1;
            const { count, newIndex } = parseQuantifier(p, i);
            i = newIndex;
            result += randomDigits(count);
        } else {
            result += p[i++];
        }
    }

    return result;
}

function generateRandomValue(field: FormField, stateCode?: string, sampleZip?: SampleZip | null): string {
    const name = field.name.toLowerCase();

    if (field.type === 'checkbox') return 'true';

    // Handle state fields before the generic select handler so we can match the actual selected state.
    const isStateField = name === 'state' || name === 'state_code' || name.endsWith('_state');
    if (isStateField) {
        if (field.type === 'select' && field.options && field.options.length > 0) {
            const match = stateCode
                ? field.options.find((o) => o.value === stateCode || o.value.toUpperCase() === stateCode)
                : null;
            return match?.value ?? field.options[0].value;
        }
        return stateCode ?? '';
    }

    if (field.type === 'select' && field.options && field.options.length > 0) {
        return field.options[0].value;
    }

    if (name.includes('start') || name.includes('effective') || name.includes('requested')) {
        const today = new Date();
        const y = today.getFullYear();
        const m = String(today.getMonth() + 1).padStart(2, '0');
        const d = String(today.getDate()).padStart(2, '0');
        return field.type === 'text' ? `${m}/${d}/${y}` : `${y}-${m}-${d}`;
    }

    if (field.type === 'date') {
        const y = randomInt(1960, 1998);
        const m = String(randomInt(1, 12)).padStart(2, '0');
        const d = String(randomInt(1, 28)).padStart(2, '0');
        return `${y}-${m}-${d}`;
    }

    if (field.type === 'hidden') return field.value ?? '';

    if (name === 'first_name' || name === 'fname' || (name.includes('first') && name.includes('name'))) {
        return randomItem(FIRST_NAMES);
    }
    if (name === 'last_name' || name === 'lname' || (name.includes('last') && name.includes('name'))) {
        return randomItem(LAST_NAMES);
    }
    if (name === 'name' || name === 'full_name' || name === 'your_name') {
        return `${randomItem(FIRST_NAMES)} ${randomItem(LAST_NAMES)}`;
    }
    if (name.includes('email')) {
        const fn = randomItem(FIRST_NAMES).toLowerCase();
        const ln = randomItem(LAST_NAMES).toLowerCase();
        return `${fn}.${ln}.test${randomInt(100, 999)}@example.com`;
    }
    if (name.includes('phone') || name.includes('mobile') || name.includes('cell')) {
        return `555${randomInt(1000000, 9999999)}`;
    }
    if (name.includes('address') || name.includes('street')) {
        if (name.includes('2')) return '';
        return `${randomInt(100, 9999)} ${randomItem(STREETS)}`;
    }
    if (name === 'city' || name.endsWith('_city')) return sampleZip?.place_name ?? '';
    if (name === 'zip' || name === 'zipcode' || name === 'zip_code' || name === 'postal_code' || name.endsWith('_zip') || name.endsWith('_zip_code')) {
        return sampleZip?.zipcode ?? String(randomInt(10000, 99999));
    }
    if (name.includes('birth') || name.includes('dob')) {
        const y = randomInt(1960, 1998);
        const m = String(randomInt(1, 12)).padStart(2, '0');
        const d = String(randomInt(1, 28)).padStart(2, '0');
        return field.type === 'text' ? `${m}/${d}/${y}` : `${y}-${m}-${d}`;
    }
    if (name.includes('ssn') || name === 'last4' || name.includes('last_4')) {
        return String(randomInt(1000, 9999));
    }
    if (name.includes('language')) return 'English';

    if (field.validation_pattern) {
        return generateFromRegex(field.validation_pattern);
    }

    return '';
}

function generateFormValues(fields: FormField[], stateCode?: string, sampleZips?: SampleZip[]): Record<string, string> {
    const sampleZip = sampleZips && sampleZips.length > 0 ? randomItem(sampleZips) : undefined;
    const values: Record<string, string> = {};
    for (const field of fields) {
        values[field.name] = generateRandomValue(field, stateCode, sampleZip);
    }
    return values;
}

function parseAffirmationField(fieldName: string): { id: number; version_id: number } | null {
    const match = fieldName.match(/^affirmation_(\d+)_v(\d+)$/);
    if (!match) return null;
    return { id: Number(match[1]), version_id: Number(match[2]) };
}

const selectClasses =
    'w-full rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm shadow-sm dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-100 disabled:cursor-not-allowed disabled:opacity-50';

const inputClasses =
    'w-full rounded-md border border-zinc-200 bg-white px-3 py-2 text-sm shadow-sm dark:border-zinc-800 dark:bg-zinc-950 dark:text-zinc-100';

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

export default function EnrollmentTest({ suppliers, webForms }: Props) {
    const [selectedSupplierId, setSelectedSupplierId] = useState<number | ''>('');
    const [selectedStateId, setSelectedStateId] = useState<number | ''>('');
    const [selectedUtilityId, setSelectedUtilityId] = useState<number | ''>('');
    const [selectedProductId, setSelectedProductId] = useState<number | ''>('');
    const [selectedWebFormSlug, setSelectedWebFormSlug] = useState<string>(webForms[0]?.slug ?? '');
    const [supplierData, setSupplierData] = useState<SupplierData | null>(null);
    const [supplierDataLoading, setSupplierDataLoading] = useState(false);
    const [webFormData, setWebFormData] = useState<WebFormData | null>(null);
    const [webFormLoading, setWebFormLoading] = useState(false);
    const [formValues, setFormValues] = useState<Record<string, string>>({});
    const [submitting, setSubmitting] = useState(false);
    const [result, setResult] = useState<{ ok: boolean; body: unknown } | null>(null);

    const filteredUtilities =
        selectedStateId && supplierData
            ? supplierData.utilities.filter((u) => u.state_id === selectedStateId)
            : supplierData?.utilities ?? [];

    const filteredProducts =
        selectedUtilityId && supplierData
            ? supplierData.products.filter((p) => p.utility_id === selectedUtilityId)
            : [];

    const selectedState = supplierData?.states.find((s) => s.id === selectedStateId);
    const selectedUtility = supplierData?.utilities.find((u) => u.id === selectedUtilityId);

    useEffect(() => {
        if (!selectedSupplierId) {
            setSupplierData(null);
            setSelectedStateId('');
            setSelectedUtilityId('');
            setSelectedProductId('');
            setWebFormData(null);
            return;
        }

        setSupplierDataLoading(true);
        setSelectedStateId('');
        setSelectedUtilityId('');
        setSelectedProductId('');
        setWebFormData(null);
        setResult(null);

        fetch(`/admin/enrollment-test/supplier-data?supplier_id=${selectedSupplierId}`)
            .then((r) => r.json() as Promise<SupplierData>)
            .then((data) => {
                setSupplierData(data);

                if (data.states.length === 1) {
                    const stateId = data.states[0].id;
                    setSelectedStateId(stateId);

                    const utilitiesInState = data.utilities.filter((u) => u.state_id === stateId);
                    if (utilitiesInState.length === 1) {
                        setSelectedUtilityId(utilitiesInState[0].id);
                    }
                }
            })
            .finally(() => setSupplierDataLoading(false));
    }, [selectedSupplierId]);

    useEffect(() => {
        if (!selectedProductId || !selectedWebFormSlug) {
            setWebFormData(null);
            setFormValues({});
            setResult(null);
            return;
        }

        setWebFormLoading(true);
        setWebFormData(null);
        setResult(null);

        fetch(`/api/public/v1/web-forms/${selectedWebFormSlug}?product_id=${selectedProductId}`)
            .then((r) => r.json() as Promise<{ data: WebFormData }>)
            .then((json) => {
                setWebFormData(json.data);
                const allFields = json.data.sections.flatMap((s) => s.fields);
                setFormValues(generateFormValues(allFields, selectedState?.code, selectedUtility?.sample_zips));
            })
            .finally(() => setWebFormLoading(false));
    }, [selectedProductId, selectedWebFormSlug]);

    const regenerate = useCallback(() => {
        if (!webFormData) return;
        const allFields = webFormData.sections.flatMap((s) => s.fields);
        setFormValues(generateFormValues(allFields, selectedState?.code, selectedUtility?.sample_zips));
    }, [webFormData, selectedState, selectedUtility]);

    async function handleSubmit(e: React.FormEvent) {
        e.preventDefault();
        if (!selectedProductId || !webFormData) return;

        setSubmitting(true);
        setResult(null);

        const affirmations: { id: number; version_id: number; accepted: boolean }[] = [];
        const data: Record<string, unknown> = {};

        for (const field of webFormData.sections.flatMap((s) => s.fields)) {
            const parsed = parseAffirmationField(field.name);
            if (parsed) {
                affirmations.push({ ...parsed, accepted: formValues[field.name] === 'true' });
            } else if (field.type !== 'hidden' || formValues[field.name]) {
                const val = formValues[field.name] ?? '';
                if (val !== '') {
                    data[field.name] = val;
                }
            }
        }

        try {
            const response = await fetch('/api/public/v1/enrollment', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
                body: JSON.stringify({
                    product_id: selectedProductId,
                    ip_address: '127.0.0.1',
                    data,
                    affirmations,
                }),
            });

            const body = await response.json();
            setResult({ ok: response.status === 201 || response.ok, body });
        } catch (err) {
            setResult({ ok: false, body: { message: String(err) } });
        } finally {
            setSubmitting(false);
        }
    }

    function handleStateChange(stateId: number | '') {
        setSelectedStateId(stateId);
        setSelectedProductId('');
        setWebFormData(null);
        setResult(null);

        if (stateId && supplierData) {
            const utilitiesInState = supplierData.utilities.filter((u) => u.state_id === stateId);
            if (utilitiesInState.length === 1) {
                setSelectedUtilityId(utilitiesInState[0].id);
            } else {
                setSelectedUtilityId('');
            }
        } else {
            setSelectedUtilityId('');
        }
    }

    function handleUtilityChange(utilityId: number | '') {
        setSelectedUtilityId(utilityId);
        setSelectedProductId('');
        setWebFormData(null);
        setResult(null);
    }

    function renderField(field: FormField) {
        const value = formValues[field.name] ?? '';
        const onChange = (val: string) => setFormValues((prev) => ({ ...prev, [field.name]: val }));
        const isAffirmation = parseAffirmationField(field.name) !== null;

        if (isAffirmation) {
            return (
                <div key={field.name} className="flex items-start gap-3 py-3 border-t border-zinc-100 dark:border-zinc-800">
                    <input
                        type="checkbox"
                        id={field.name}
                        checked={value === 'true'}
                        onChange={(e) => onChange(e.target.checked ? 'true' : 'false')}
                        className="mt-0.5 size-4 shrink-0 rounded border-zinc-300 dark:border-zinc-700"
                    />
                    <label
                        htmlFor={field.name}
                        className="text-xs leading-relaxed text-zinc-600 dark:text-zinc-400"
                        dangerouslySetInnerHTML={{ __html: field.label }}
                    />
                </div>
            );
        }

        return (
            <div key={field.name} className="grid grid-cols-[220px_1fr] gap-3 items-start py-2 border-t border-zinc-100 dark:border-zinc-800 first:border-0">
                <label htmlFor={field.name} className="text-sm font-medium text-zinc-700 dark:text-zinc-300 pt-2 leading-tight">
                    {field.label}
                    {field.required && <span className="ml-0.5 text-red-500">*</span>}
                    {field.type === 'hidden' && (
                        <span className="ml-1 text-xs font-normal text-zinc-400">(hidden)</span>
                    )}
                </label>
                <div className="space-y-1">
                    {field.type === 'select' && field.options ? (
                        <select
                            id={field.name}
                            value={value}
                            onChange={(e) => onChange(e.target.value)}
                            className={selectClasses}
                        >
                            <option value="">— select —</option>
                            {field.options.map((opt) => (
                                <option key={opt.value} value={opt.value}>
                                    {opt.label}
                                </option>
                            ))}
                        </select>
                    ) : field.type === 'checkbox' ? (
                        <input
                            type="checkbox"
                            id={field.name}
                            checked={value === 'true'}
                            onChange={(e) => onChange(e.target.checked ? 'true' : 'false')}
                            className="size-4 rounded border-zinc-300 dark:border-zinc-700"
                        />
                    ) : field.type === 'hidden' ? (
                        <input
                            type="text"
                            value={value}
                            onChange={(e) => onChange(e.target.value)}
                            className={`${inputClasses} font-mono text-xs text-zinc-500`}
                        />
                    ) : (
                        <input
                            id={field.name}
                            type={field.type === 'email' ? 'email' : field.type === 'date' ? 'date' : 'text'}
                            value={value}
                            onChange={(e) => onChange(e.target.value)}
                            placeholder={field.placeholder ?? ''}
                            className={inputClasses}
                        />
                    )}
                    {field.help_text && (
                        <p className="text-xs text-zinc-500 dark:text-zinc-400">{field.help_text}</p>
                    )}
                </div>
            </div>
        );
    }

    return (
        <AppLayout breadcrumbs={breadcrumbs}>
            <Head title="Enrollment Test" />

            <h1 className="sr-only">Enrollment Test</h1>

            <div className="space-y-6">
                <HeadingSmall
                    title="Enrollment Test"
                    description="Inject a test enrollment through the public API endpoint"
                />

                {/* Step 1: Product selection */}
                <div className="rounded-md border border-zinc-200 bg-white p-5 dark:border-zinc-800 dark:bg-zinc-950">
                    <h2 className="mb-4 text-sm font-semibold text-zinc-700 dark:text-zinc-300">
                        1. Select Product
                    </h2>

                    <div className="grid grid-cols-2 gap-4 sm:grid-cols-4">
                        <div className="space-y-1">
                            <label className="text-xs font-medium text-zinc-600 dark:text-zinc-400">
                                Supplier
                            </label>
                            <select
                                value={selectedSupplierId}
                                onChange={(e) =>
                                    setSelectedSupplierId(e.target.value ? Number(e.target.value) : '')
                                }
                                className={selectClasses}
                            >
                                <option value="">— select —</option>
                                {suppliers.map((s) => (
                                    <option key={s.id} value={s.id}>
                                        {s.name}
                                    </option>
                                ))}
                            </select>
                        </div>

                        <div className="space-y-1">
                            <label className="text-xs font-medium text-zinc-600 dark:text-zinc-400">
                                State
                            </label>
                            <select
                                value={selectedStateId}
                                onChange={(e) =>
                                    handleStateChange(e.target.value ? Number(e.target.value) : '')
                                }
                                disabled={!supplierData || supplierDataLoading}
                                className={selectClasses}
                            >
                                <option value="">
                                    {supplierDataLoading ? 'Loading…' : '— select —'}
                                </option>
                                {supplierData?.states.map((s) => (
                                    <option key={s.id} value={s.id}>
                                        {s.code} – {s.name}
                                    </option>
                                ))}
                            </select>
                        </div>

                        <div className="space-y-1">
                            <label className="text-xs font-medium text-zinc-600 dark:text-zinc-400">
                                Utility
                            </label>
                            <select
                                value={selectedUtilityId}
                                onChange={(e) =>
                                    handleUtilityChange(e.target.value ? Number(e.target.value) : '')
                                }
                                disabled={!selectedStateId}
                                className={selectClasses}
                            >
                                <option value="">— select —</option>
                                {filteredUtilities.map((u) => (
                                    <option key={u.id} value={u.id}>
                                        {u.name}
                                    </option>
                                ))}
                            </select>
                        </div>

                        <div className="space-y-1">
                            <label className="text-xs font-medium text-zinc-600 dark:text-zinc-400">
                                Product
                            </label>
                            <select
                                value={selectedProductId}
                                onChange={(e) =>
                                    setSelectedProductId(e.target.value ? Number(e.target.value) : '')
                                }
                                disabled={!selectedUtilityId || filteredProducts.length === 0}
                                className={selectClasses}
                            >
                                <option value="">— select —</option>
                                {filteredProducts.map((p) => (
                                    <option key={p.id} value={p.id}>
                                        {productProperName(p.name)}
                                    </option>
                                ))}
                            </select>
                        </div>
                    </div>

                    {webForms.length > 1 && (
                        <div className="mt-4 max-w-xs space-y-1">
                            <label className="text-xs font-medium text-zinc-600 dark:text-zinc-400">
                                Web Form
                            </label>
                            <select
                                value={selectedWebFormSlug}
                                onChange={(e) => setSelectedWebFormSlug(e.target.value)}
                                className={selectClasses}
                            >
                                {webForms.map((f) => (
                                    <option key={f.slug} value={f.slug}>
                                        {f.name}
                                    </option>
                                ))}
                            </select>
                        </div>
                    )}
                </div>

                {/* Loading state */}
                {webFormLoading && (
                    <div className="rounded-md border border-zinc-200 bg-white p-5 dark:border-zinc-800 dark:bg-zinc-950">
                        <p className="text-sm text-zinc-500 dark:text-zinc-400">Loading form fields…</p>
                    </div>
                )}

                {/* Step 2: Enrollment form */}
                {webFormData && !webFormLoading && (
                    <form onSubmit={handleSubmit}>
                        <div className="rounded-md border border-zinc-200 bg-white p-5 dark:border-zinc-800 dark:bg-zinc-950">
                            <div className="mb-5 flex items-center justify-between">
                                <h2 className="text-sm font-semibold text-zinc-700 dark:text-zinc-300">
                                    2. Enrollment Form — {webFormData.name}
                                </h2>
                                <button
                                    type="button"
                                    onClick={regenerate}
                                    className="rounded-md border border-zinc-200 bg-white px-3 py-1.5 text-xs font-medium text-zinc-600 hover:bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-400 dark:hover:bg-zinc-800"
                                >
                                    Regenerate Random Data
                                </button>
                            </div>

                            <div className="space-y-6">
                                {webFormData.sections.map((section) => (
                                    <div key={section.name ?? 'unsectioned'}>
                                        {section.label && (
                                            <h3 className="mb-1 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
                                                {section.label}
                                            </h3>
                                        )}
                                        {section.description && (
                                            <p className="mb-2 text-xs text-zinc-500 dark:text-zinc-400">
                                                {section.description}
                                            </p>
                                        )}
                                        <div>{section.fields.map((field) => renderField(field))}</div>
                                    </div>
                                ))}
                            </div>

                            <div className="mt-6 flex justify-end">
                                <button
                                    type="submit"
                                    disabled={submitting}
                                    className="rounded-md bg-zinc-900 px-4 py-2 text-sm font-medium text-white hover:bg-zinc-800 disabled:opacity-50 dark:bg-zinc-100 dark:text-zinc-900 dark:hover:bg-zinc-200"
                                >
                                    {submitting ? 'Submitting…' : 'Submit Enrollment'}
                                </button>
                            </div>
                        </div>
                    </form>
                )}

                {/* Result panel */}
                {result && (
                    <div
                        className={`rounded-md border p-5 ${
                            result.ok
                                ? 'border-green-200 bg-green-50 dark:border-green-800 dark:bg-green-950/30'
                                : 'border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-950/30'
                        }`}
                    >
                        <h2
                            className={`mb-3 text-sm font-semibold ${
                                result.ok
                                    ? 'text-green-800 dark:text-green-300'
                                    : 'text-red-800 dark:text-red-300'
                            }`}
                        >
                            {result.ok ? 'Enrollment Submitted' : 'Submission Failed'}
                        </h2>
                        <pre className="overflow-x-auto text-xs font-mono leading-relaxed text-zinc-800 dark:text-zinc-200 whitespace-pre-wrap">
                            {JSON.stringify(result.body, null, 2)}
                        </pre>
                    </div>
                )}
            </div>
        </AppLayout>
    );
}
