import React, {
    forwardRef,
    useEffect,
    useImperativeHandle,
    useRef,
} from "react";
import { cn } from "~/lib/utils";

export interface TextBoxProps
    extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange" | "value"> {
    value: string;
    onChange: (value: string) => void;
    placeholder?: string;
    wrapperClassName?: string;
    inputClassName?: string;
    disabled?: boolean;
    autoFocus?: boolean;
    spellCheck?: boolean;
}

export const TextBox = forwardRef<HTMLDivElement, TextBoxProps>(
    (
        {
            value,
            onChange,
            placeholder,
            wrapperClassName,
            inputClassName,
            disabled = false,
            autoFocus = false,
            spellCheck = true,
            onInput,
            onBlur,
            onFocus,
            ...rest
        },
        ref,
    ) => {
        const localRef = useRef<HTMLDivElement>(null);
        useImperativeHandle(ref, () => localRef.current as HTMLDivElement);

        // Function to handle DOM updates
        const updateDOM = (newValue: string) => {
            if (localRef.current) {
                // Only update if different to avoid selection issues
                if (localRef.current.textContent !== newValue) {
                    localRef.current.textContent = newValue;

                    // Clear any <br> elements if the content is empty
                    if (
                        !newValue &&
                        localRef.current.innerHTML.includes("<br>")
                    ) {
                        localRef.current.innerHTML = "";
                    }
                }
            }
        };

        // Update DOM when value prop changes
        useEffect(() => {
            updateDOM(value);
        }, [value]);

        useEffect(() => {
            if (autoFocus && localRef.current) {
                localRef.current.focus();
            }
        }, [autoFocus]);

        const handleInput = (event: React.FormEvent<HTMLDivElement>) => {
            const newValue = event.currentTarget.textContent || "";

            // Handle the case where the content is empty but contains a <br>
            if (!newValue && event.currentTarget.innerHTML.includes("<br>")) {
                event.currentTarget.innerHTML = "";
            }

            onChange(newValue);
            onInput?.(event);
        };

        const handlePaste = (event: React.ClipboardEvent<HTMLDivElement>) => {
            event.preventDefault();
            const text = event.clipboardData.getData("text/plain");

            // Use document.execCommand to maintain undo stack
            document.execCommand("insertText", false, text);

            // Manually trigger input event
            const inputEvent = new Event("input", { bubbles: true });
            event.currentTarget.dispatchEvent(inputEvent);
        };

        return (
            <div
                className={cn(
                    "overflow-y-auto overflow-x-hidden w-full min-h-6",
                    wrapperClassName,
                )}
                onClick={() => localRef.current?.focus()}
            >
                <div
                    ref={localRef}
                    contentEditable={!disabled}
                    onInput={handleInput}
                    onPaste={handlePaste}
                    onBlur={onBlur}
                    onFocus={onFocus}
                    className={cn(
                        "outline-none break-all",
                        "empty:before:content-[attr(data-placeholder)] empty:before:text-muted-foreground empty:before:cursor-text",
                        disabled && "cursor-not-allowed opacity-50",
                        inputClassName,
                    )}
                    data-placeholder={placeholder}
                    role="textbox"
                    aria-multiline="true"
                    aria-disabled={disabled}
                    aria-placeholder={placeholder}
                    spellCheck={spellCheck}
                    suppressContentEditableWarning
                    tabIndex={0}
                    {...rest}
                />
            </div>
        );
    },
);

TextBox.displayName = "TextBox";

export default TextBox;
