import React, { ComponentProps, MutableRefObject } from "react";
import { RawEditorOptions, TinyMCE, Editor } from "./tinymce";
import { twMerge } from "tailwind-merge";
import twuiSlugToNormalText from "../../utils/slug-to-normal-text";
import Border from "../../elements/Border";
import useTinyMCE from "./useTinyMCE";

export type TinyMCEEditorProps<KeyType extends string> = {
    options?: RawEditorOptions;
    editorRef?: React.MutableRefObject<Editor | null>;
    setEditor?: React.Dispatch<React.SetStateAction<Editor>>;
    wrapperProps?: React.DetailedHTMLProps<
        React.HTMLAttributes<HTMLDivElement>,
        HTMLDivElement
    >;
    wrapperWrapperProps?: React.DetailedHTMLProps<
        React.HTMLAttributes<HTMLDivElement>,
        HTMLDivElement
    >;
    borderProps?: ComponentProps<typeof Border>;
    defaultValue?: string;
    name?: KeyType;
    changeHandler?: (content: string) => void;
    showLabel?: boolean;
    useParentCSS?: boolean;
    placeholder?: string;
    refreshDependencyArray?: any[];
};

/**
 * # Tiny MCE Editor Component
 * @className_wrapper twui-rte-wrapper
 */
export default function TinyMCEEditor<KeyType extends string>({
    options,
    editorRef: passedEditorRef,
    setEditor: passedSetEditor,
    wrapperProps,
    defaultValue,
    changeHandler,
    wrapperWrapperProps,
    borderProps,
    name,
    showLabel,
    useParentCSS,
    placeholder,
    refreshDependencyArray,
}: TinyMCEEditorProps<KeyType>) {
    const { tinyMCE } = useTinyMCE();

    const editorComponentRef = React.useRef<HTMLDivElement>(null);
    const editorRef: MutableRefObject<Editor | null> =
        passedEditorRef || React.useRef(null);

    const EDITOR_VALUE_CHANGE_TIMEOUT = 500;

    const FINAL_HEIGHT = options?.height || 500;
    const [themeReady, setThemeReady] = React.useState(false);
    const [ready, setReady] = React.useState(false);
    const [darkMode, setDarkMode] = React.useState(false);
    const [refresh, setRefresh] = React.useState(0);
    const [editor, setEditor] = React.useState<Editor>();

    const title = name ? twuiSlugToNormalText(name) : "Rich Text";

    React.useEffect(() => {
        if (!tinyMCE) {
            return;
        }

        const htmlClassName = document.documentElement.className;

        if (htmlClassName.match(/dark/i)) setDarkMode(true);

        setTimeout(() => {
            setThemeReady(true);
        }, 200);
    }, [tinyMCE]);

    let valueTimeout: any;

    const id = crypto.randomUUID();

    React.useEffect(() => {
        if (!editorComponentRef.current || !themeReady || !tinyMCE) {
            return;
        }

        const baseUrl = "https://www.datasquirel.com/tinymce-public";

        tinyMCE.init({
            height: FINAL_HEIGHT,
            menubar: false,
            plugins:
                "advlist lists link image charmap preview anchor searchreplace visualblocks code fullscreen insertdatetime media table code help wordcount",
            toolbar:
                "undo redo | blocks | bold italic underline link image | bullist numlist outdent indent | removeformat code searchreplace wordcount preview insertdatetime",
            content_style:
                "body { font-family:Helvetica,Arial,sans-serif; font-size:14px; background-color: transparent }",
            init_instance_callback: (editor) => {
                setEditor(editor as any);
                if (editorRef) {
                    editorRef.current = editor;
                    passedSetEditor?.(editor);
                }
                if (defaultValue) editor.setContent(defaultValue);
                setReady(true);

                // editor.on("change", (e) => {
                //     changeHandler?.(editor.getContent());
                // });

                editor.on("input", (e) => {
                    if (changeHandler) {
                        window.clearTimeout(valueTimeout);

                        valueTimeout = setTimeout(() => {
                            changeHandler(editor.getContent());
                        }, EDITOR_VALUE_CHANGE_TIMEOUT);
                    }
                });

                if (useParentCSS) {
                    useParentStyles(editor);
                }
            },
            base_url: baseUrl,
            body_class: "twui-tinymce",
            placeholder,
            relative_urls: true,
            remove_script_host: true,
            convert_urls: false,
            ...options,
            license_key: "gpl",
            target: editorComponentRef.current,
            content_css: darkMode ? "dark" : undefined,
            skin: darkMode ? "oxide-dark" : undefined,
        });

        return function () {
            if (!ready) return;

            const instance = editorComponentRef.current
                ? tinyMCE?.get(editorComponentRef.current?.id)
                : undefined;
            instance?.remove();
        };
    }, [tinyMCE, themeReady, refresh, ...(refreshDependencyArray || [])]);

    React.useEffect(() => {
        const instance = editorRef.current;

        if (instance) {
            instance.setContent(defaultValue || "");
        }
    }, [defaultValue]);

    return (
        <div
            {...wrapperWrapperProps}
            className={twMerge(
                "relative w-full [&_.tox-tinymce]:!border-none",
                "bg-background-light dark:bg-background-dark",
                wrapperWrapperProps?.className,
            )}
            onInput={(e) => {
                console.log(`Input Detected`);
            }}
        >
            {showLabel && (
                <label
                    className={twMerge(
                        "absolute z-10 -top-[7px] left-[10px] px-2 text-xs",
                        "bg-background-light dark:bg-background-dark text-gray-500",
                        "dark:text-white/80 rounded",
                    )}
                    htmlFor={id}
                >
                    {title}
                </label>
            )}
            <Border
                {...borderProps}
                className={twMerge(
                    "dark:border-white/30 p-0 pt-2",
                    borderProps?.className,
                )}
            >
                <div
                    {...wrapperProps}
                    ref={editorComponentRef}
                    style={{
                        height:
                            String(FINAL_HEIGHT).replace(/[^\d]/g, "") + "px",
                        ...wrapperProps?.style,
                    }}
                    className={twMerge(
                        "bg-slate-200 dark:bg-slate-700 rounded-sm w-full",
                        "twui-rte-wrapper",
                    )}
                    id={id}
                ></div>
            </Border>
        </div>
    );
}

function useParentStyles(editor: Editor) {
    const doc = editor.getDoc();
    const parentStylesheets = document.styleSheets;

    for (const sheet of parentStylesheets) {
        try {
            if (sheet.href) {
                const link = doc.createElement("link");
                link.rel = "stylesheet";
                link.href = sheet.href;
                doc.head.appendChild(link);
            } else {
                const rules = sheet.cssRules || sheet.rules;
                if (rules) {
                    const style = doc.createElement("style");
                    for (const rule of rules) {
                        try {
                            style.appendChild(doc.createTextNode(rule.cssText));
                        } catch (e) {
                            console.warn("Could not copy CSS rule:", rule, e);
                        }
                    }
                    doc.head.appendChild(style);
                }
            }
        } catch (e) {
            console.warn("Error processing stylesheet:", sheet, e);
        }
    }
}
