import style from "./style.module.scss";
import {Preview} from "@/components/preview";
import cn from "classnames";
import {useState, useRef, MutableRef, useEffect} from "preact/hooks";
import {JSX} from "preact";
import {
    User,
    Type,
    Bold,
    Italic,
    Underline,
    ChevronRight,
    EyeOff,
    Smile,
    Image,
} from "preact-feather";
import {smileysMap} from "@/utils/smileys";
import {Button} from "@/components/button";
import {Input} from "@/components/input";
import {Alert} from "@/components/alert";

const iconSize = 14;
// const initialText = "> zefgze https://image.noelshack.com/fichiers/2018/13/4/1522325846-jesusopti.png\n" +
//     "> zgfzreg :-)))\n" +
//     "> > ergerg\n" +
//     "zezefzef\n" +
//     "<spoil>loool</spoil> AHI";

export function Wysiwyg(props: {
    showTitle: boolean,
    onSubmit: (user: string, title: string, text: string) => void,
    disabled?: boolean,
    initialText?: string,
    text?: string,
    setText?: (text: string) => void,
}) {
    const [errors, setErrors] = useState<string[]>([]);
    const [title, setTitle] = useState("");
    const [user, setUser] = useState("");
    const [text, setText] = props.text !== undefined && props.setText !== undefined ? [props.text, props.setText] : useState(props.initialText || "");
    const [accordion, setAccordion] = useState<"smileys"|"stickers"|false>(false);

    // Create a ref for the textarea
    const textareaRef = useRef<HTMLTextAreaElement | null>(null);
    const selectionRange = useRef<[start: number, end: number]|null>(null);

    // // Example function to demonstrate interaction with the ref
    // const focusTextarea = () => {
    //     if (textareaRef.current) {
    //         textareaRef.current.focus();
    //     }
    // };

    useEffect(() => {
        if (textareaRef.current && selectionRange.current) {
            const [start, end] = selectionRange.current;
            textareaRef.current.setSelectionRange(start, end);
            selectionRange.current = null;
        }
    }, [text])

    const bold = createAction(textareaRef, (start, end) => {
        const tag = "'''";

        setText(insertAt(insertAt(text, tag, start), tag, end + tag.length));
        selectionRange.current = [start + tag.length, end + tag.length];
    });

    const italic = createAction(textareaRef, (start, end) => {
        const tag = "''";

        setText(insertAt(insertAt(text, tag, start), tag, end + tag.length));
        selectionRange.current = [start + tag.length, end + tag.length];
    });

    const underline = createAction(textareaRef, (start, end) => {
        const startTag = "<u>";
        const endTag = "</u>";

        setText(insertAt(insertAt(text, startTag, start), endTag, end + startTag.length));
        selectionRange.current = [start + startTag.length, end + startTag.length];
    });

    const quote = createAction(textareaRef, (start, end) => {
        const lines = text.split("\n");
        const newLines: string[] = [];
        let charCount = 0;
        let quoteEnd = 0;
        let addedChars = 0;
        for (const line of lines) {
            charCount += line.length + 1; // Add "\n"
            if (charCount > start && (charCount - line.length) <= end + 1) {
                newLines.push(`> ${line}`);
                addedChars += 2;
                quoteEnd = charCount;
            } else {
                newLines.push(line);
            }
        }

        setText(newLines.join("\n"));
        selectionRange.current = [quoteEnd + addedChars - 1, quoteEnd + addedChars - 1];
    });

    const spoil = createAction(textareaRef, (start, end) => {
        const startTag = "<spoil>";
        const endTag = "</spoil>";

        setText(insertAt(insertAt(text, startTag, start), endTag, end + startTag.length));
        selectionRange.current = [start + startTag.length, end + startTag.length];
    });

    return (
        <div>
            <Alert lines={errors}/>
            <Input
                type="text"
                icon={User}
                value={user}
                onChange={v => setUser(v as string)}
                placeholder="Pseudo"
            />
            {
                props.showTitle ? (
                    <Input
                        type="text"
                        icon={Type}
                        value={title}
                        onChange={v => setTitle(v as string)}
                        placeholder="Titre du sujet"
                    />
                ) : null
            }
            <div className={style.container}>
                <div className={style.toolbar}>
                    <div className={style.toolbarGroup}>
                        <div className={style.buttonContainer} title="Gras" onMouseDown={bold}>
                            <Bold size={iconSize}/>
                        </div>
                        <div className={style.buttonContainer} title="Italique" onMouseDown={italic}>
                            <Italic size={iconSize}/>
                        </div>
                        <div className={style.buttonContainer} title="Souligné" onMouseDown={underline}>
                            <Underline size={iconSize}/>
                        </div>
                    </div>
                    <div className={style.toolbarGroup}>
                        <div className={style.buttonContainer} title="Citation" onMouseDown={quote}>
                            <ChevronRight size={iconSize}/>
                        </div>
                        <div className={style.buttonContainer} title="Spoil" onMouseDown={spoil}>
                            <EyeOff size={iconSize}/>
                        </div>
                    </div>
                    <div className={style.toolbarGroup}>
                        <div
                            className={style.buttonContainer}
                            title="Smileys"
                            onClick={() => {
                                setAccordion(accordion ? false : "smileys")
                            }}
                        >
                            <Smile size={iconSize}/>
                        </div>
                        <div className={style.buttonContainer} title="Stickers">
                            <Image size={iconSize}/>
                        </div>
                    </div>
                </div>
                <div className={cn(style.accordion, {[style.accordionOpened]: accordion})}>
                    <SmileyList
                        text={text}
                        setText={setText}
                        textareaRef={textareaRef}
                        selectionRange={selectionRange}
                    />
                </div>
                <div className={style.editor}>
                    <textarea
                        className={style.textarea}
                        placeholder="Saisissez un message…"
                        name="wysiwyg"
                        id="wysiwyg"
                        cols="30"
                        rows="10"
                        value={text}
                        onInput={(e) => setText((e.target as HTMLTextAreaElement).value)}
                        ref={textareaRef} // Attach ref to textarea
                    />
                </div>
            </div>
            <div className={cn(style.container, style.previewContainer)}>
                <Preview raw={text}/>
            </div>
            <Button
                secondary={true}
                onClick={() => {
                    const errors: string[] = [];

                    if(user.length < 2) {
                        errors.push("Le pseudo doit se composer au minimum de 3 caractères");
                    }

                    if(user.match(/[^a-zA-Z0-9_-]/)) {
                        errors.push("Le pseudo doit uniquement contenir les caractères suivant: a-z, A-Z, 0-9, _ et -");
                    }

                    if(props.showTitle && title.length < 2) {
                        errors.push("Le titre du sujet doit se composer au minimum de 3 caractères");
                    }

                    if(text.length < 2) {
                        errors.push("Le text du sujet doit se composer au minimum de 3 caractères");
                    }

                    setErrors(errors);

                    if(errors.length > 0) {
                        return;
                    }

                    props.onSubmit(user, title, text);
                    setUser("");
                    setTitle("");
                    setText("");
                }}
                disabled={props.disabled}
            >
                Poster
            </Button>
        </div>
    );
}

function SmileyList(props: {
    text: string,
    setText: (text: string) => void,
    textareaRef: MutableRef<HTMLTextAreaElement | null>,
    selectionRange: MutableRef<[start: number, end: number]|null>,
}) {
    // const addSmiley = createAction(props.textareaRef, (start, end) => {
    //     const startTag = "<u>";
    //     const endTag = "</u>";
    //
    //     props.setText(insertAt(insertAt(props.text, startTag, start), endTag, end + startTag.length));
    //     props.selectionRange.current = [start + startTag.length, end + startTag.length];
    // });

    const addSmiley: (smiley: string) => JSX.MouseEventHandler<HTMLDivElement> = (smiley) => (e) => {
        e.preventDefault(); // Do not lose the focus on textarea
        if (props.textareaRef.current) {
            props.setText(insertAt(props.text, smiley, props.textareaRef.current.selectionStart));
            props.selectionRange.current = [props.textareaRef.current.selectionStart + smiley.length, props.textareaRef.current.selectionStart + smiley.length];
            props.textareaRef.current.focus();
        }
    }

    return (
        <div className={style.smileyList}>
            {smileysMap.map((smiley) => (
                <div onMouseDown={addSmiley(` ${smiley[0]}`)}>
                    <img
                        src={`https://image.jeuxvideo.com/smileys_img/${smiley[1]}.gif`}
                        alt={smiley[0]}
                    />
                </div>
            ))}
        </div>
    )
}

function createAction(
    ref: MutableRef<HTMLTextAreaElement | null>,
    callback: (start: number, end: number) => void
): JSX.MouseEventHandler<HTMLDivElement> {
    return (e) => {
        e.preventDefault(); // Do not lose the focus on textarea
        if (ref.current) {
            callback(ref.current.selectionStart, ref.current.selectionEnd);
            ref.current.focus();
        }
    }
}

function insertAt(originalString: string, substring: string, position: number): string {
    return originalString.slice(0, position) + substring + originalString.slice(position);
}