import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";

export interface RichTextInputProps {
    style?: React.CSSProperties;
    onChange?: (value: string) => void;
    onKeyDown?: (event: React.KeyboardEvent) => void;
    onPaste?: (event: React.ClipboardEvent) => void;
    placeholder?: string;
    autoFocus?: boolean;
}


export const RichTextInput = forwardRef((props : any, ref) => {
    const editableDivRef = useRef<HTMLDivElement>(null);

    useImperativeHandle(ref, () => ({
        getValue,
        insertHTML,
        focus,
        clear,
        insertHTMLInCurrentCarretPosition
    }));

    useEffect(() => {
        if(props.autoFocus && editableDivRef.current){
            focusEditableElement(editableDivRef.current);
        }
    }, [props.autoFocus]);

    const focus = () => {
        if(editableDivRef.current){
            focusEditableElement(editableDivRef.current);
        }
    }

    const insertHTMLInCurrentCarretPosition = (html: string) => {
        if(!editableDivRef.current){
            return;
        }
        if(document.activeElement !== editableDivRef.current){
            focusEditableElement(editableDivRef.current);
        }
        document.execCommand('insertHTML', false, html);
    }

    const clear = () => {
        if(editableDivRef.current){
            editableDivRef.current.innerHTML = "";
        }
        if(props.onChange){
            props.onChange("");
        }   
    }

    const focusEditableElement = (element: HTMLElement) => {
        /**
         * Focus to the end of the contenteditable element
         */
        const range = document.createRange();
        const sel = window.getSelection();
        range.selectNodeContents(element);
        range.collapse(false);
        sel?.removeAllRanges();
        sel?.addRange(range);
        element.focus();
    }

    const insertHTML = (html: string) => {
        if(!editableDivRef.current) return;
        let div = document.createElement("div");
        div.innerHTML = html;
        if(props.style && props.style.fontSize){
            /**
             * Prepare all elements to have the same font size as the editable div
             */
            div.querySelectorAll('*').forEach(el => {
                el.setAttribute('style', `
                    font-size: ${props.style?.fontSize}px;
                    vertical-align: sub;
                    display: inline-block;
                    margin-left: 1px;
                    margin-right: 1px;
                    user-select: none;
                    `);
                el.setAttribute('width', '17');
                el.setAttribute('height', '17');
            });
        }
        let preparedHtml = div.innerHTML;
        //let carret = saveCarretPosition(editableDivRef.current);
        editableDivRef.current.innerHTML += preparedHtml;
        //editableDivRef.current.focus();
        //insertHtmlAtCarretPosition(preparedHtml);
        if(props.onChange){
            props.onChange(getValue());
        }
        //focusEditableElement(editableDivRef.current, carret);
    }

    const getValue = () : string => {
        if(!editableDivRef.current) return "";
        editableDivRef.current.querySelectorAll('*').forEach(el => {
            if(el.tagName === 'BR'){
                el.textContent = '\n';
                return;
            }
            if(!el.hasAttribute("data")){
                el.textContent = '';
                return;
            }
            let text = el.getAttribute("data") || '';
            el.textContent = text;
        });
        let content = editableDivRef.current.textContent || "";
        if(content.endsWith('\n') && content.length == 1){
            /**
             * Remove trailing new line added by contenteditable div
             * (bug in some browsers includes electron)
             */
            content = content.slice(0, -1);
        }
        return content || "";
    }


    // const onCopy = (event : React.ClipboardEvent) => {
    //     //event.preventDefault();
    //     //console.info("COPY EVENT", event);
    //     //let value = getValue();
    //     //console.info("COPY VALUE", value);
    //     //event.clipboardData.setData('text/plain', value);
    // }

    const onPaste = (event: React.ClipboardEvent) => {
        event.preventDefault();
        let text = event.clipboardData.getData('text/plain');
        if(text.trim() != '' && editableDivRef.current){
            const html = text
                .replace(/&/g, "&amp;")
                .replace(/</g, "&lt;")
                .replace(/>/g, "&gt;")
                .replace(/"/g, "&quot;")
                .replace(/'/g, "&#039;")
                .replace(/\n/g, "<br>");
            document.execCommand('insertHTML', false, html);
            if(props.onChange){
                props.onChange(getValue());
            }
            event.preventDefault();
            return;
        }
        if(event.clipboardData.items[0].kind !== 'string'){
            event.preventDefault();
        }
        if(props.onPaste){
            props.onPaste(event);
        }
    }

    const onKeyPress = (event : React.KeyboardEvent) => {
        if (event.keyCode == 13 && event.shiftKey == true) {
            //event.preventDefault(); 
            //addLineBreak();
            //return;
        }
        requestAnimationFrame(() => {
            if(editableDivRef.current?.innerHTML.trim() == '<br>'){
                editableDivRef.current.innerHTML = '';
            }
            if(props.onChange){
                props.onChange(getValue());
            }
        });
        if(props.onKeyDown){
            props.onKeyDown(event);
        }
    }

    return (
        <div style={{
            width: props.style?.width || '100%',
            maxWidth: props.style?.width || '100%',
            display: 'inline-block',
            position: 'relative',
        }}>
            <div 
                onDrag={e => e.preventDefault()}
                onPaste={onPaste}
                //onCopy={onCopy}
                onKeyDown={onKeyPress}
                ref={editableDivRef}
                contentEditable={true} 
                suppressContentEditableWarning
                style={{
                    overflowX: 'hidden',
                    maxHeight: 150,
                    maxWidth: '100%',
                    overflowY: 'auto',
                    wordWrap: 'break-word',
                    whiteSpace: 'pre-wrap',
                    verticalAlign: 'middle',
                    boxSizing: 'border-box',
                    outline: 'none',
                    ...props.style,
                    width: '100%',
                }}
            ></div>
            {getValue() == "" && props.placeholder && (
                <div style={{
                    position: 'absolute',
                    top: 10,
                    left: 10,
                    pointerEvents: 'none',
                    color: '#888',
                    userSelect: 'none',
                    fontSize: props.style?.fontSize || 14,
                }}>
                    {props.placeholder}
                </div>
            )}
        </div>
    )
});