import React from "react";
import Hook from "../hook";
import AceEditor from "react-ace";
import { Ace } from "ace-builds";
import { IAceOptions, ICommand, IEditorProps, IMarker } from "react-ace";
import * as AceBuilds from "ace-builds";
import "ace-builds/webpack-resolver";
import "ace-builds/src-noconflict/mode-javascript";
import "ace-builds/src-noconflict/mode-typescript";
import "ace-builds/src-noconflict/mode-json";
import "ace-builds/src-noconflict/mode-html";
import "ace-builds/src-noconflict/mode-xml";
import "ace-builds/src-noconflict/mode-sass";
import "ace-builds/src-noconflict/mode-css";
import "ace-builds/src-noconflict/mode-mysql";
import "ace-builds/src-noconflict/mode-python";
import "ace-builds/src-noconflict/mode-ruby";
import "ace-builds/src-noconflict/mode-markdown";
import "ace-builds/src-noconflict/mode-handlebars";
import "ace-builds/src-noconflict/mode-golang";
import "ace-builds/src-noconflict/mode-csharp";
import "ace-builds/src-noconflict/mode-elixir";
import "ace-builds/src-noconflict/theme-github";
import "ace-builds/src-noconflict/theme-monokai";
import "ace-builds/src-noconflict/ext-language_tools";

export type Language =
    'javascript' |
    'typescript' |
    'json' |
    'html' |
    'xml' |
    'sass' |
    'css' |
    'mysql' |
    'python' |
    'ruby' |
    'markdown' |
    'handlebars' |
    'golang' |
    'csharp' |
    'elixir';

export type CodeEditorProps = {
    language: Language,
    name?: string;
    style?: React.CSSProperties;
    height?: string;
    width?: string;
    className?: string;
    fontSize?: number | string;
    showGutter?: boolean;
    showPrintMargin?: boolean;
    highlightActiveLine?: boolean;
    focus?: boolean;
    cursorStart?: number;
    wrapEnabled?: boolean;
    readOnly?: boolean;
    minLines?: number;
    maxLines?: number;
    navigateToFileEnd?: boolean;
    debounceChangePeriod?: number;
    enableBasicAutocompletion?: boolean | string[];
    enableLiveAutocompletion?: boolean | string[];
    tabSize?: number;
    value?: string;
    placeholder?: string;
    defaultValue?: string;
    scrollMargin?: number[];
    enableSnippets?: boolean;
    onSelectionChange?: (value: any, event?: any) => void;
    onCursorChange?: (value: any, event?: any) => void;
    onInput?: (event?: any) => void;
    onLoad?: (editor: Ace.Editor) => void;
    onValidate?: (annotations: Ace.Annotation[]) => void;
    onBeforeLoad?: (ace: typeof AceBuilds) => void;
    onChange?: (value: string, event?: any) => void;
    onSelection?: (selectedText: string, event?: any) => void;
    onCopy?: (value: string) => void;
    onPaste?: (value: string) => void;
    onFocus?: (event: any, editor?: Ace.Editor) => void;
    onBlur?: (event: any, editor?: Ace.Editor) => void;
    onScroll?: (editor: IEditorProps) => void;
    editorProps?: IEditorProps;
    setOptions?: IAceOptions;
    keyboardHandler?: string;
    commands?: ICommand[];
    annotations?: Ace.Annotation[];
    markers?: IMarker[];
};

export const CodeEditor: React.FC<CodeEditorProps> = ({ language, onChange, ...props }) => {
    const [theme] = Hook.useTheme();
    const [value, setValue] = React.useState(props.value)

    const timer = React.useRef<NodeJS.Timeout>();

    React.useEffect(() => {
        setValue(props.value);
    }, [props.value])

    const handleChange = (value: string) => {
        setValue(value)

        if (onChange) {
            clearTimeout(timer.current);

            timer.current = setTimeout(() => {
                onChange(value)
            }, 500)
        }
    }

    return (
        <AceEditor
            {...props}
            mode={language}
            theme={
                theme.palette.mode === 'light'
                    ? 'github'
                    : 'monokai'
            }
            value={value}
            onChange={handleChange}
        />
    )
}