<template>
    <div class="w-full">
        <NElement
            tag="div"
            class="et-outline p-2 rounded border outline-none text-left overflow-auto transition-all duration-300"
            @keydown="onKeyDown"
            @keypress="onKeyPressed"
            @keyup="onKeyUp"
            contenteditable
            ref="el"
        >
            <p data-level="0" data-title="第一章"></p>
        </NElement>
    </div>
</template>
<script setup lang="ts">
import { Ref, computed, onMounted, reactive, ref, watch } from 'vue'
import { useMutationObserver, useDebounceFn } from '@vueuse/core'
import { NButton, NConfigProvider, NElement, useThemeVars } from 'naive-ui'
// @ts-ignore
import * as NumberToChinese from '@siakhooi/number-to-chinese-words'

const props = defineProps({
    modelValue: {
        type: Array<any>,
        default: (): any[] => []
    }
})
watch(
    () => props.modelValue,
    (v, ov) => {
        console.log('watch', v)
        if (JSON.stringify(v) !== JSON.stringify(chapters)) {
            update(props.modelValue)
        }
    }
)
const themeVars = useThemeVars()
const el: Ref<any> = ref(null)
const et = computed(() => {
    return el.value?.$el as HTMLElement
})

onMounted(() => {
    console.log('outline editor mounted')
    useMutationObserver(
        et.value,
        mutations => {
            console.log(mutations)
            if (mutations.flatMap(m => Array.from(m.addedNodes).concat(Array.from(m.removedNodes))).length > 0) {
                arrange()
            } else if (mutations.filter(m => m.type === 'characterData').length > 0) {
                arrange()
            }
            arrange()
        },
        {
            attributes: true,
            childList: true,
            subtree: true,
            characterData: true
        }
    )
    update(props.modelValue)
})

const chapters: any[] = reactive([])

const emit = defineEmits(['update:modelValue'])
watch(chapters, v => {
    emit('update:modelValue', v)
})
const arrange = useDebounceFn(() => {
    console.log('arrange')
    const levels = [0, 0, 0, 0]
    chapters.splice(0, chapters.length)
    for (const child of Array.from(et.value?.children || [])) {
        const e = child as Element
        const level = parseInt(e.getAttribute('data-level') || '0')
        levels[level] = levels[level] + 1
        for (let i = level + 1; i < levels.length; i++) {
            levels[i] = 0
        }
        let title
        if (level === 0) {
            title = '第' + NumberToChinese.convertNumber(levels[0], { removeLeadingOne: levels[level] > 1 }) + '章'
        } else {
            title = levels.slice(0, level + 1).join('.')
        }
        if (e.getAttribute('data-title') !== title) e.setAttribute('data-title', title)

        let node: any
        let parent = chapters
        levels.slice(0, level + 1).forEach((v: number) => {
            node = parent[v - 1]
            if (!node) {
                node = {
                    children: []
                }
                parent[v - 1] = node
            }
            parent = node.children
        })
        if (node) node.title = e.textContent
    }
    emit('update:modelValue', chapters)
}, 10)

function update(chaptersData: any) {
    console.log('update', chaptersData)
    chaptersData = chaptersData || [{ title: '', level: 0 }]
    if (chaptersData.length === 0) {
        chaptersData.push({ title: '', level: 0 })
    }
    const list: any[] = []
    function _update(_data: any, level: number) {
        _data.forEach((e: any) => {
            list.push({
                title: e.title,
                level
            })
            if (e.children) _update(e.children, level + 1)
        })
    }
    _update(chaptersData, 0)
    et.value?.replaceChildren(
        ...list.map(e => {
            const p = document.createElement('p')
            p.setAttribute('data-level', e.level.toString())
            p.textContent = e.title
            return p
        })
    )

    arrange()
    console.log(list)
}

function onKeyDown(e: KeyboardEvent) {
    const sel = window.getSelection()!
    let node = sel!.anchorNode!
    if (node?.nodeName !== 'P') {
        node = node.parentNode!
    }
    const idx = Array.from(node?.parentNode?.children || []).indexOf(node as any)

    if (e.key === 'Enter') {
        if (e.shiftKey) {
            e.preventDefault()
            return
        }
        // e.preventDefault()
        // const p = document.createElement('p')
        // et.value?.insertBefore(p, node!.parentNode!.children[idx + 1])
        // let prev
        // if (idx === 0) {
        //     prev = node
        // } else {
        //     prev = node!.parentNode!.children[idx - 1]
        // }
        // p.setAttribute('data-title', '第二章')
        // p.setAttribute('data-level', (prev as Element)?.getAttribute('data-level') || '0')
        // range.setStart(p, 0)
        // range.collapse(true)
        // sel?.removeAllRanges()
        // sel?.addRange(range)
    } else if (e.key === 'Tab') {
        e.preventDefault()
        if (idx === 0) return
        let level = parseInt((node as Element).getAttribute('data-level') || '0')
        level += e.shiftKey ? -1 : 1
        level = Math.min(Math.max(0, level), 3)
        ;(node as Element).setAttribute('data-level', level.toString())
        arrange()
        console.log(e)
    } else if (e.key === 'Backspace') {
        if (!node.textContent && node.parentNode?.children.length === 1) {
            e.preventDefault()
        }
        //
    }
}
function onKeyPressed(e: KeyboardEvent) {}
function onKeyUp(e: KeyboardEvent) {}
</script>
<style lang="less" scoped>
.et-outline {
    border-color: var(--border-color);
    min-height: 488px;
    max-height: 488px;
    &:focus {
        border-color: var(--primary-color);
    }
    :deep(p) {
        &::before {
            content: attr(data-title) ' ';
            opacity: 0.6;
        }
        &[data-level='1'] {
            padding-left: 16px;
        }
        &[data-level='2'] {
            padding-left: 32px;
        }
        &[data-level='3'] {
            padding-left: 48px;
        }
    }
}
</style>
