<div 
    class={"border border-darkborderc relative n-scroll focus-within:border-borderc rounded-md shadow-sm text-textcolor bg-transparent focus-within:ring-borderc focus-within:ring-2 focus-within:outline-none transition-colors duration-200 z-20 focus-within:z-40" + ((className) ? (' ' + className) : '')} 
    class:text-sm={size === 'sm' || (size === 'default' && $textAreaTextSize === 1)}
    class:text-md={size === 'md' || (size === 'default' && $textAreaTextSize === 2)}
    class:text-lg={size === 'lg' || (size === 'default' && $textAreaTextSize === 3)}
    class:text-xl={size === 'xl'}
    class:text-xs={size === 'xs' || (size === 'default' && $textAreaTextSize === 0)}
    class:w-full={fullwidth}
    class:h-20={height === '20' || (height === 'default' && $textAreaSize === -5)}
    class:h-24={height === '24' || (height === 'default' && $textAreaSize === -4)}
    class:h-28={height === '28' || (height === 'default' && $textAreaSize === -3)}
    class:h-32={height === '32' || (height === 'default' && $textAreaSize === -2)}
    class:h-36={height === '36' || (height === 'default' && $textAreaSize === -1)}
    class:h-40={height === 'default' && $textAreaSize === 0}
    class:h-44={height === 'default' && $textAreaSize === 1}
    class:h-48={height === 'default' && $textAreaSize === 2}
    class:h-52={height === 'default' && $textAreaSize === 3}
    class:h-56={height === 'default' && $textAreaSize === 4}
    class:h-60={height === 'default' && $textAreaSize === 5}
    class:h-full={height === 'full'}
    class:min-h-20={height === '20' || (height === 'default' && $textAreaSize === -5)}
    class:min-h-24={height === '24' || (height === 'default' && $textAreaSize === -4)}
    class:min-h-28={height === '28' || (height === 'default' && $textAreaSize === -3)}
    class:min-h-32={height === '32' || (height === 'default' && $textAreaSize === -2)}
    class:min-h-36={height === '36' || (height === 'default' && $textAreaSize === -1)}
    class:min-h-40={height === 'default' && $textAreaSize === 0}
    class:min-h-48={height === 'default' && $textAreaSize === 1}
    class:min-h-56={height === 'default' && $textAreaSize === 2}
    class:min-h-64={height === 'default' && $textAreaSize === 3}
    class:min-h-72={height === 'default' && $textAreaSize === 4}
    class:min-h-80={height === 'default' && $textAreaSize === 5}
    class:mb-4={margin === 'bottom'}
    class:mb-2={margin === 'both'}
    class:mt-4={margin === 'top'}
    class:mt-2={margin === 'both'}
    bind:this={highlightDom}
    onfocusout={() => {
        hideAutoComplete()
    }}
>
    {#if !highlight}
        <textarea
            class="w-full h-full bg-transparent focus-within:outline-none resize-none absolute top-0 left-0 z-50 overflow-y-auto"
            class:px-4={padding}
            class:py-2={padding}
            {autocomplete}
            {placeholder}
            id={id}
            bind:value={value}
            oninput={(e) => {
                if(optimaizedInput){
                    if(inpa++ > 10){
                        value = e.currentTarget.value
                        inpa = 0
                        onInput()
                    }
                }
                else{
                    value = e.currentTarget.value
                    onInput()
                }
            }}
            onchange={(e) => {
                if(optimaizedInput){
                    value = e.currentTarget.value
                    onInput()
                }
            }}
></textarea>
    {:else if isFirefox}
        <div
            class="w-full h-full bg-transparent focus-within:outline-none resize-none absolute top-0 left-0 z-50 overflow-y-auto px-4 py-2 break-words whitespace-pre-wrap"
            contenteditable="true"
            bind:textContent={value}
            onkeydown={(e) => {
                handleKeyDown(e)
                onInput()
            }}
            oninput={(e) => {
                autoComplete()
            }}
            onpaste={(e) => {
                e.preventDefault()
                const text = e.clipboardData.getData('text/plain')
                if(text){
                    insertTextAtSelection(text)
                }
            }}
            bind:this={inputDom}
            translate="no"
        >{value ?? ''}</div>
    {:else}
        <div
            class="w-full h-full bg-transparent focus-within:outline-none resize-none absolute top-0 left-0 z-50 overflow-y-auto px-4 py-2 break-words whitespace-pre-wrap"
            contenteditable="plaintext-only"
            bind:innerText={value}
            onkeydown={(e) => {
                handleKeyDown(e)
                onInput()
            }}
            oninput={(e) => {
                autoComplete()
            }}
            bind:this={inputDom}
            translate="no"
        >{value ?? ''}</div>
    {/if}
    <div class="hidden absolute z-100 bg-bgcolor border border-darkborderc p-2 flex-col" bind:this={autoCompleteDom}>
        {#each autocompleteContents as content, i}
            <button class="w-full text-left py-1 px-2 bg-bgcolor" class:text-blue-500={selectingAutoComplete === i} onclick={() => {
                insertContent(content)
            }}>{content}</button>
        {/each}
    </div>
</div>
<script lang="ts">
    import { run } from 'svelte/legacy';

    import { textAreaSize, textAreaTextSize } from 'src/ts/gui/guisize'
    import { highlighter, getNewHighlightId, removeHighlight, AllCBS } from 'src/ts/gui/highlight'
    import { isMobile } from 'src/ts/storage/globalApi';
    import { isFirefox, sleep } from 'src/ts/util';
    import { onDestroy, onMount } from 'svelte';
    interface Props {
        size?: 'xs'|'sm'|'md'|'lg'|'xl'|'default';
        autocomplete?: 'on'|'off';
        placeholder?: string;
        value: string;
        id?: string;
        padding?: boolean;
        margin?: "none"|"top"|"bottom"|"both";
        onInput?: any;
        fullwidth?: boolean;
        height?: '20'|'24'|'28'|'32'|'36'|'full'|'default';
        className?: string;
        optimaizedInput?: boolean;
        highlight?: boolean;
    }

    let {
        size = 'default',
        autocomplete = 'off',
        placeholder = '',
        value = $bindable(),
        id = undefined,
        padding = true,
        margin = "none",
        onInput = () => {},
        fullwidth = false,
        height = 'default',
        className = '',
        optimaizedInput = true,
        highlight = false
    }: Props = $props();
    let selectingAutoComplete = $state(0)
    let highlightId = highlight ? getNewHighlightId() : 0
    let inpa = $state(0)
    let highlightDom: HTMLDivElement = $state()
    let optiValue = $state(value)
    let autoCompleteDom: HTMLDivElement = $state()
    let autocompleteContents:string[] = $state([])
    let inputDom: HTMLDivElement = $state()

    const autoComplete = () => {
        if(isMobile){
            return
        }
        //autocomplete
        selectingAutoComplete = 0
        const sel = window.getSelection()
        if(!sel){
            return
        }

        const range = sel.getRangeAt(0)

        if(range){
            const qValue = (range.startContainer).textContent
            const splited = qValue.substring(0, range.startOffset).split('{{')
            if(splited.length === 1){
                hideAutoComplete()
                return
            }
            const qText = splited.pop()
            let filtered = AllCBS.filter((cb) => cb.startsWith(qText))
            if(filtered.length === 0){
                hideAutoComplete()
                return
            }
            filtered = filtered.slice(0, 10)
            autocompleteContents = filtered
        }

        const hlRect = highlightDom.getBoundingClientRect()
        const rect = range.getBoundingClientRect()
        if(rect.top === 0 && rect.left === 0){
            hideAutoComplete()
            return
        }
        const top = rect.top - hlRect.top + 15
        const left = rect.left - hlRect.left
        autoCompleteDom.style.top = top + 'px'
        autoCompleteDom.style.left = left + 'px'
        autoCompleteDom.style.display = 'flex'
    }

    const insertContent = (insertContent:string, type:'autoComplete'|'paste' = 'autoComplete') => {
        console.log(insertContent)
        const sel = window.getSelection()
        if(sel){
            const range = sel.getRangeAt(0)
            let content = (range.startContainer).textContent
            let contentStart = content.substring(0, range.startOffset)
            let contentEnd = content.substring(range.startOffset)
            if(type === 'autoComplete'){
                contentStart = contentStart.substring(0, contentStart.lastIndexOf('{{'))
                if(insertContent.endsWith(':')){
                    insertContent = `{{${insertContent}:`
                }
                else if(insertContent.startsWith('#')){
                    insertContent = `{{${insertContent} `
                }
                else{
                    insertContent = `{{${insertContent}}}`
                }
            }

            const cons = contentStart + insertContent + contentEnd
            range.startContainer.textContent = cons
            hideAutoComplete()

            try {
                sel.collapse(range.startContainer, contentStart.length + insertContent.length)                
            } catch (error) {}
            //invoke onInput
            
            try {
                inputDom.dispatchEvent(new Event('input'))
                inputDom.dispatchEvent(new Event('change'))
            } catch (error) {}
        }
    }

    const hideAutoComplete = () => {
        autoCompleteDom.style.display = 'none'
        selectingAutoComplete = 0
        autocompleteContents = []
    }

    onMount(() => {
        highlighter(highlightDom, highlightId)
    })

    onDestroy(() => {
        removeHighlight(highlightId)
    })

    const highlightChange = async (value:string, highlightId:number) => {
        await sleep(1)
        highlighter(highlightDom, highlightId)
    }

    const handleKeyDown = (e:KeyboardEvent) => {
        if(autocompleteContents.length >= 1){
            switch(e.key){
                case 'ArrowDown':
                    selectingAutoComplete = Math.min(selectingAutoComplete + 1, autocompleteContents.length - 1)
                    e.preventDefault()
                    return
                case 'ArrowUp':
                    selectingAutoComplete = Math.max(selectingAutoComplete - 1, 0)
                    e.preventDefault()
                    return
                case 'Enter':
                case 'Tab':
                    e.preventDefault()
                    insertContent(autocompleteContents[selectingAutoComplete])
                    return
                case 'Escape':
                    hideAutoComplete()
                    return
            }
        }
        if(e.key === 'Enter' && isFirefox){
            e.stopPropagation()
            e.preventDefault()
            insertTextAtSelection('\n')
        }
    }

    function insertTextAtSelection(txt:string) {

        txt = txt.replace(/\r/g, '')

        let div = inputDom;
        let sel = window.getSelection();
        let text = div.textContent;
        let before = Math.min(sel.focusOffset, sel.anchorOffset);
        let after = Math.max(sel.focusOffset, sel.anchorOffset);
        let afterStr = text.substring(after);
        if (afterStr == "") afterStr = "\n";
        div.textContent = text.substring(0, before) + txt + afterStr;
        sel.removeAllRanges();
        let range = document.createRange();
        range.setStart(div.childNodes[0], before + txt.length);
        range.setEnd(div.childNodes[0], before + txt.length);
        sel.addRange(range);
        try {
            inputDom.dispatchEvent(new Event('input'))
            inputDom.dispatchEvent(new Event('change'))
        } catch (error) {}
    }
        
    run(() => {
        optiValue = value
    });
    run(() => {
        highlightChange(value, highlightId)
    });

</script>