import { memo, useEffect, useRef, useState, type InputHTMLAttributes } from 'react';
import {
    dangerSoftButtonClassName,
    formControlClassName,
    formHelpClassName,
    formLabelClassName,
    primarySoftButtonClassName,
} from '@admin/components/ui/field-styles';
import { WysiwygEditor } from '@admin/components/ui/forms/wysiwyg-editor';
import { documentQuillToolbarOptions } from '@admin/lib/load-quill-editor';
import { cn } from '@admin/lib/utils';
import {
    emptyDocumentBlock,
    type DocumentBlock,
    type DocumentBlockType,
    type DocumentBlockTypeOption,
    type DocumentField,
    type DocumentTableColumn,
} from '@admin/types/document';

type DocumentBlockBuilderProps = {
    blocks: DocumentBlock[];
    fields: DocumentField[];
    blockTypeOptions: DocumentBlockTypeOption[];
    disabled?: boolean;
    onChange: (blocks: DocumentBlock[]) => void;
};

function fieldOptions(fields: DocumentField[]): Array<{ value: string; label: string }> {
    return fields
        .filter((field) => field.key.trim() !== '')
        .map((field) => ({
            value: field.key,
            label: field.label ? `${field.label} (${field.key})` : field.key,
        }));
}

function blockLabel(type: DocumentBlockType, options: DocumentBlockTypeOption[]): string {
    return options.find((option) => option.value === type)?.label ?? type;
}

/** Keeps typing local; commits to parent after a short pause so the preview doesn’t block input. */
function SmoothTextInput({
    value,
    onChange,
    delayMs = 180,
    className,
    ...props
}: {
    value: string;
    onChange: (value: string) => void;
    delayMs?: number;
} & Omit<InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange'>) {
    const [draft, setDraft] = useState(value);
    const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

    useEffect(() => {
        setDraft(value);
    }, [value]);

    useEffect(() => {
        return () => {
            if (timerRef.current) {
                clearTimeout(timerRef.current);
            }
        };
    }, []);

    const flush = (next: string) => {
        if (timerRef.current) {
            clearTimeout(timerRef.current);
            timerRef.current = null;
        }

        if (next !== value) {
            onChange(next);
        }
    };

    return (
        <input
            {...props}
            className={className}
            value={draft}
            onChange={(event) => {
                const next = event.target.value;
                setDraft(next);

                if (timerRef.current) {
                    clearTimeout(timerRef.current);
                }

                timerRef.current = setTimeout(() => onChange(next), delayMs);
            }}
            onBlur={() => flush(draft)}
        />
    );
}

function SmoothWysiwyg({
    value,
    onChange,
    disabled,
}: {
    value: string;
    onChange: (html: string) => void;
    disabled?: boolean;
}) {
    const [draft, setDraft] = useState(value);
    const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

    useEffect(() => {
        setDraft(value);
    }, [value]);

    useEffect(() => {
        return () => {
            if (timerRef.current) {
                clearTimeout(timerRef.current);
            }
        };
    }, []);

    if (disabled) {
        return (
            <div
                className="document-rich-text rounded-sm border border-defaultborder p-3 text-sm"
                dangerouslySetInnerHTML={{ __html: value || '—' }}
            />
        );
    }

    return (
        <WysiwygEditor
            label="Static content"
            value={draft}
            onChange={(html) => {
                setDraft(html);

                if (timerRef.current) {
                    clearTimeout(timerRef.current);
                }

                timerRef.current = setTimeout(() => onChange(html), 220);
            }}
            placeholder="Write paragraph content with lists…"
            minHeightClassName="min-h-[140px]"
            toolbar={documentQuillToolbarOptions}
        />
    );
}

export const DocumentBlockBuilder = memo(function DocumentBlockBuilder({
    blocks,
    fields,
    blockTypeOptions,
    disabled = false,
    onChange,
}: DocumentBlockBuilderProps) {
    const mappedFields = fieldOptions(fields);
    const [selectedType, setSelectedType] = useState<DocumentBlockType>('paragraph');
    const [openId, setOpenId] = useState<string | null>(blocks[0]?.id ?? null);

    const updateBlock = (index: number, patch: Partial<DocumentBlock>) => {
        onChange(blocks.map((block, blockIndex) => (blockIndex === index ? { ...block, ...patch } : block)));
    };

    const moveBlock = (index: number, direction: -1 | 1) => {
        const nextIndex = index + direction;

        if (nextIndex < 0 || nextIndex >= blocks.length) {
            return;
        }

        const next = [...blocks];
        const [moved] = next.splice(index, 1);
        next.splice(nextIndex, 0, moved);
        onChange(next);
        setOpenId(moved.id);
    };

    const addBlock = () => {
        const block = emptyDocumentBlock(selectedType);
        onChange([...blocks, block]);
        setOpenId(block.id);
    };

    const updateColumn = (blockIndex: number, columnIndex: number, patch: Partial<DocumentTableColumn>) => {
        const block = blocks[blockIndex];
        const columns = [...(block.columns ?? [])];
        columns[columnIndex] = { ...columns[columnIndex], ...patch };
        updateBlock(blockIndex, { columns });
    };

    return (
        <div className="document-builder-editor">
            <div className="mb-3">
                <p className={formLabelClassName}>Page blocks</p>
                <p className={formHelpClassName}>
                    Add sections, map your fields, and watch the live preview update on the right.
                </p>
            </div>

            {!disabled && (
                <div className="mb-4 flex flex-wrap items-end gap-2">
                    <label className="min-w-[180px] flex-1 text-sm">
                        <span className={formHelpClassName}>Block type</span>
                        <select
                            className={cn(formControlClassName, 'mt-1')}
                            value={selectedType}
                            onChange={(event) => setSelectedType(event.target.value as DocumentBlockType)}
                        >
                            {blockTypeOptions.map((option) => (
                                <option key={option.value} value={option.value}>
                                    {option.label}
                                </option>
                            ))}
                        </select>
                    </label>
                    <button type="button" className={cn(primarySoftButtonClassName, 'h-10')} onClick={addBlock}>
                        <i className="ri-add-line me-1" />
                        Add block
                    </button>
                </div>
            )}

            {blocks.length === 0 ? (
                <div className="rounded-sm border border-dashed border-defaultborder p-6 text-center dark:border-white/10">
                    <p className="mb-1 text-sm font-medium">No blocks yet</p>
                    <p className={formHelpClassName}>Start with a Header, then add headings, fields, or a table.</p>
                </div>
            ) : (
                <div className="space-y-2">
                    {blocks.map((block, index) => {
                        const isOpen = openId === block.id;

                        return (
                            <div
                                key={block.id || `${block.type}-${index}`}
                                className="rounded-sm border border-defaultborder dark:border-white/10"
                            >
                                <div className="flex items-center gap-2 border-b border-defaultborder px-3 py-2 dark:border-white/10">
                                    <button
                                        type="button"
                                        className="flex min-w-0 flex-1 items-center gap-2 text-left text-sm font-medium"
                                        onClick={() => setOpenId(isOpen ? null : block.id)}
                                    >
                                        <i className={isOpen ? 'ri-arrow-down-s-line' : 'ri-arrow-right-s-line'} />
                                        <span className="truncate">
                                            {index + 1}. {blockLabel(block.type, blockTypeOptions)}
                                        </span>
                                    </button>
                                    {!disabled && (
                                        <div className="flex shrink-0 gap-1">
                                            <button
                                                type="button"
                                                className={primarySoftButtonClassName}
                                                disabled={index === 0}
                                                title="Move up"
                                                onClick={() => moveBlock(index, -1)}
                                            >
                                                <i className="ri-arrow-up-line" />
                                            </button>
                                            <button
                                                type="button"
                                                className={primarySoftButtonClassName}
                                                disabled={index === blocks.length - 1}
                                                title="Move down"
                                                onClick={() => moveBlock(index, 1)}
                                            >
                                                <i className="ri-arrow-down-line" />
                                            </button>
                                            <button
                                                type="button"
                                                className={dangerSoftButtonClassName}
                                                title="Remove"
                                                onClick={() => {
                                                    const next = blocks.filter((_, blockIndex) => blockIndex !== index);
                                                    onChange(next);
                                                    if (openId === block.id) {
                                                        setOpenId(next[Math.max(0, index - 1)]?.id ?? null);
                                                    }
                                                }}
                                            >
                                                <i className="ri-delete-bin-line" />
                                            </button>
                                        </div>
                                    )}
                                </div>

                                {isOpen && (
                                    <div className="space-y-3 p-3">
                                        {block.type === 'header' && (
                                            <div className="flex flex-wrap gap-4 text-sm">
                                                {[
                                                    ['show_logo', 'Logo', block.show_logo !== false],
                                                    ['show_title', 'Title badge', block.show_title !== false],
                                                    ['show_contact', 'Contact lines', block.show_contact !== false],
                                                ].map(([key, label, checked]) => (
                                                    <label key={String(key)} className="inline-flex items-center gap-2">
                                                        <input
                                                            type="checkbox"
                                                            className="ti-form-checkbox"
                                                            checked={Boolean(checked)}
                                                            disabled={disabled}
                                                            onChange={(event) =>
                                                                updateBlock(index, {
                                                                    [key as string]: event.target.checked,
                                                                })
                                                            }
                                                        />
                                                        {label}
                                                    </label>
                                                ))}
                                            </div>
                                        )}

                                        {block.type === 'heading' && (
                                            <div className="grid gap-3 sm:grid-cols-2">
                                                <label className="block text-sm">
                                                    <span className={formHelpClassName}>Static text</span>
                                                    <SmoothTextInput
                                                        className={cn(formControlClassName, 'mt-1')}
                                                        value={block.text ?? ''}
                                                        disabled={disabled}
                                                        onChange={(text) => updateBlock(index, { text })}
                                                    />
                                                </label>
                                                <label className="block text-sm">
                                                    <span className={formHelpClassName}>Or map field</span>
                                                    <select
                                                        className={cn(formControlClassName, 'mt-1')}
                                                        value={block.field ?? ''}
                                                        disabled={disabled}
                                                        onChange={(event) =>
                                                            updateBlock(index, { field: event.target.value })
                                                        }
                                                    >
                                                        <option value="">None</option>
                                                        {mappedFields.map((field) => (
                                                            <option key={field.value} value={field.value}>
                                                                {field.label}
                                                            </option>
                                                        ))}
                                                    </select>
                                                </label>
                                            </div>
                                        )}

                                        {block.type === 'paragraph' && (
                                            <div className="space-y-3">
                                                <label className="block text-sm">
                                                    <span className={formHelpClassName}>Map rich field (optional)</span>
                                                    <select
                                                        className={cn(formControlClassName, 'mt-1')}
                                                        value={block.field ?? ''}
                                                        disabled={disabled}
                                                        onChange={(event) =>
                                                            updateBlock(index, { field: event.target.value })
                                                        }
                                                    >
                                                        <option value="">Use static content below</option>
                                                        {mappedFields.map((field) => (
                                                            <option key={field.value} value={field.value}>
                                                                {field.label}
                                                            </option>
                                                        ))}
                                                    </select>
                                                </label>
                                                {!block.field && (
                                                    <SmoothWysiwyg
                                                        value={block.html ?? ''}
                                                        disabled={disabled}
                                                        onChange={(html) => updateBlock(index, { html })}
                                                    />
                                                )}
                                            </div>
                                        )}

                                        {block.type === 'field' && (
                                            <div className="grid gap-3 sm:grid-cols-2">
                                                <label className="block text-sm">
                                                    <span className={formHelpClassName}>Field</span>
                                                    <select
                                                        className={cn(formControlClassName, 'mt-1')}
                                                        value={block.field ?? ''}
                                                        disabled={disabled}
                                                        onChange={(event) =>
                                                            updateBlock(index, { field: event.target.value })
                                                        }
                                                    >
                                                        <option value="">Select field</option>
                                                        {mappedFields.map((field) => (
                                                            <option key={field.value} value={field.value}>
                                                                {field.label}
                                                            </option>
                                                        ))}
                                                    </select>
                                                </label>
                                                <label className="mt-6 inline-flex items-center gap-2 text-sm">
                                                    <input
                                                        type="checkbox"
                                                        className="ti-form-checkbox"
                                                        checked={block.show_label !== false}
                                                        disabled={disabled}
                                                        onChange={(event) =>
                                                            updateBlock(index, { show_label: event.target.checked })
                                                        }
                                                    />
                                                    Show label
                                                </label>
                                            </div>
                                        )}

                                        {block.type === 'fields' && (
                                            <div className="space-y-3">
                                                <label className="inline-flex items-center gap-2 text-sm">
                                                    <input
                                                        type="checkbox"
                                                        className="ti-form-checkbox"
                                                        checked={block.show_labels !== false}
                                                        disabled={disabled}
                                                        onChange={(event) =>
                                                            updateBlock(index, { show_labels: event.target.checked })
                                                        }
                                                    />
                                                    Show labels
                                                </label>
                                                <div className="grid gap-2 sm:grid-cols-2">
                                                    {mappedFields.map((field) => {
                                                        const checked = (block.fields ?? []).includes(field.value);

                                                        return (
                                                            <label
                                                                key={field.value}
                                                                className="inline-flex items-center gap-2 text-sm"
                                                            >
                                                                <input
                                                                    type="checkbox"
                                                                    className="ti-form-checkbox"
                                                                    checked={checked}
                                                                    disabled={disabled}
                                                                    onChange={(event) => {
                                                                        const current = block.fields ?? [];
                                                                        const next = event.target.checked
                                                                            ? [...current, field.value]
                                                                            : current.filter((key) => key !== field.value);
                                                                        updateBlock(index, { fields: next });
                                                                    }}
                                                                />
                                                                {field.label}
                                                            </label>
                                                        );
                                                    })}
                                                </div>
                                            </div>
                                        )}

                                        {block.type === 'table' && (
                                            <div className="space-y-3">
                                                {(block.columns ?? []).map((column, columnIndex) => (
                                                    <div
                                                        key={`${block.id}-col-${columnIndex}`}
                                                        className="grid gap-2 sm:grid-cols-2"
                                                    >
                                                        <SmoothTextInput
                                                            className={formControlClassName}
                                                            placeholder="Column label"
                                                            value={column.label}
                                                            disabled={disabled}
                                                            onChange={(label) =>
                                                                updateColumn(index, columnIndex, { label })
                                                            }
                                                        />
                                                        <div className="flex gap-2">
                                                            <select
                                                                className={formControlClassName}
                                                                value={column.field}
                                                                disabled={disabled}
                                                                onChange={(event) =>
                                                                    updateColumn(index, columnIndex, {
                                                                        field: event.target.value,
                                                                    })
                                                                }
                                                            >
                                                                <option value="">Map field</option>
                                                                {mappedFields.map((field) => (
                                                                    <option key={field.value} value={field.value}>
                                                                        {field.label}
                                                                    </option>
                                                                ))}
                                                            </select>
                                                            {!disabled && (
                                                                <button
                                                                    type="button"
                                                                    className={dangerSoftButtonClassName}
                                                                    onClick={() =>
                                                                        updateBlock(index, {
                                                                            columns: (block.columns ?? []).filter(
                                                                                (_, i) => i !== columnIndex,
                                                                            ),
                                                                        })
                                                                    }
                                                                >
                                                                    <i className="ri-delete-bin-line" />
                                                                </button>
                                                            )}
                                                        </div>
                                                    </div>
                                                ))}
                                                {!disabled && (
                                                    <button
                                                        type="button"
                                                        className={primarySoftButtonClassName}
                                                        onClick={() =>
                                                            updateBlock(index, {
                                                                columns: [
                                                                    ...(block.columns ?? []),
                                                                    { label: '', field: '' },
                                                                ],
                                                            })
                                                        }
                                                    >
                                                        <i className="ri-add-line me-1" />
                                                        Add column
                                                    </button>
                                                )}
                                            </div>
                                        )}

                                        {block.type === 'footer' && (
                                            <div className="flex flex-wrap gap-4 text-sm">
                                                <label className="inline-flex items-center gap-2">
                                                    <input
                                                        type="checkbox"
                                                        className="ti-form-checkbox"
                                                        checked={block.show_thank_you !== false}
                                                        disabled={disabled}
                                                        onChange={(event) =>
                                                            updateBlock(index, { show_thank_you: event.target.checked })
                                                        }
                                                    />
                                                    Thank-you image
                                                </label>
                                                <label className="inline-flex items-center gap-2">
                                                    <input
                                                        type="checkbox"
                                                        className="ti-form-checkbox"
                                                        checked={block.show_qr !== false}
                                                        disabled={disabled}
                                                        onChange={(event) =>
                                                            updateBlock(index, { show_qr: event.target.checked })
                                                        }
                                                    />
                                                    Verification QR
                                                </label>
                                            </div>
                                        )}

                                        {(block.type === 'divider' || block.type === 'signature') && (
                                            <p className={formHelpClassName}>
                                                {block.type === 'divider'
                                                    ? 'Renders a horizontal rule using the document accent colour.'
                                                    : 'Uses the signature image and show-signature setting from Design.'}
                                            </p>
                                        )}
                                    </div>
                                )}
                            </div>
                        );
                    })}
                </div>
            )}
        </div>
    );
});
