import { useEffect, useRef } from 'react';

import {
    formErrorClassName,
    formFieldClassName,
    formHelpClassName,
    formLabelClassName,
} from '@admin/components/ui/field-styles';
import { ensureQuillEditor, quillToolbarOptions, type QuillInstance } from '@admin/lib/load-quill-editor';
import { cn } from '@admin/lib/utils';

type WysiwygEditorProps = {
    id?: string;
    label: string;
    value: string;
    onChange: (html: string) => void;
    error?: string;
    helpText?: string;
    placeholder?: string;
    minHeightClassName?: string;
};

export function WysiwygEditor({
    id,
    label,
    value,
    onChange,
    error,
    helpText,
    placeholder = 'Write content…',
    minHeightClassName = 'min-h-[220px]',
}: WysiwygEditorProps) {
    const inputId = id ?? label.toLowerCase().replace(/\s+/g, '-');
    const containerRef = useRef<HTMLDivElement>(null);
    const quillRef = useRef<QuillInstance | null>(null);
    const onChangeRef = useRef(onChange);
    const lastEmittedValue = useRef(value);
    const syncingRef = useRef(false);

    onChangeRef.current = onChange;

    useEffect(() => {
        let cancelled = false;
        let changeHandler: (() => void) | null = null;

        const init = async () => {
            if (!containerRef.current) {
                return;
            }

            const Quill = await ensureQuillEditor();

            if (cancelled || !containerRef.current) {
                return;
            }

            containerRef.current.innerHTML = '';

            const quill = new Quill(containerRef.current, {
                modules: {
                    toolbar: quillToolbarOptions,
                },
                theme: 'snow',
                placeholder,
            });

            quillRef.current = quill;

            if (value) {
                syncingRef.current = true;
                quill.clipboard.dangerouslyPasteHTML(value);
                syncingRef.current = false;
                lastEmittedValue.current = quill.root.innerHTML;
            }

            changeHandler = () => {
                if (syncingRef.current) {
                    return;
                }

                const html = quill.root.innerHTML;
                const normalized = html === '<p><br></p>' ? '' : html;
                lastEmittedValue.current = normalized;
                onChangeRef.current(normalized);
            };

            quill.on('text-change', changeHandler);
        };

        void init();

        return () => {
            cancelled = true;

            if (quillRef.current && changeHandler) {
                quillRef.current.off('text-change', changeHandler);
            }

            quillRef.current = null;

            if (containerRef.current) {
                containerRef.current.innerHTML = '';
            }
        };
    }, [placeholder]);

    useEffect(() => {
        const quill = quillRef.current;

        if (!quill || value === lastEmittedValue.current) {
            return;
        }

        syncingRef.current = true;
        quill.clipboard.dangerouslyPasteHTML(value || '');
        syncingRef.current = false;
        lastEmittedValue.current = value;
    }, [value]);

    return (
        <div className={cn(formFieldClassName, 'mb-4')}>
            <label htmlFor={inputId} className={formLabelClassName}>
                {label}
            </label>
            <div
                className={cn(
                    'rounded-sm border border-gray-200 bg-white dark:border-white/10 dark:bg-bgdark',
                    error && 'border-danger',
                )}
                aria-invalid={Boolean(error)}
                aria-describedby={error ? `${inputId}-error` : helpText ? `${inputId}-help` : undefined}
            >
                <div ref={containerRef} id={inputId} className={cn(minHeightClassName)} />
            </div>
            {error && (
                <span id={`${inputId}-error`} className={formErrorClassName}>
                    {error}
                </span>
            )}
            {helpText && !error && (
                <p id={`${inputId}-help`} className={formHelpClassName}>
                    {helpText}
                </p>
            )}
        </div>
    );
}
