<template>
    <div ref="keyboardWrapRef" class="keyboard-wrap" @click="focusInput">
        <el-input ref="inputRef" v-model="model" @keyup.enter="handleEnter" :disabled="disabled" v-bind="$attrs">
            <template v-for="(item, index) in $slots" :key="index" #[index]>
                <slot :name="index"></slot>
            </template>
        </el-input>
    </div>
    <el-popover v-if="visible" :visible="true" :virtual-ref="inputRef" virtual-triggering placement="bottom" :width="width" :show-arrow="false" :hide-after="0" popper-style="padding: 0px;color:#000" popper-class="keyboard-popper" @after-enter="keyboardInit">
        <div class="simple-keyboard"></div>
    </el-popover>
</template>

<script setup lang="ts">
import Keyboard from 'simple-keyboard'
import 'simple-keyboard/build/css/index.css'
import layout from 'simple-keyboard-layouts/build/layouts/chinese.js'
defineOptions({
    inheritAttrs: false
})
const model = defineModel<string>()
const emits = defineEmits(['onChange', 'enter', 'close', 'focus'])
const props = defineProps({
    layoutName: {
        type: String,
        default: 'default'
    },
    // 保留几位小数 layoutName为number时生效
    precision: {
        type: Number,
        default: 10
    },
    // 获取焦点打开键盘
    isOpen: {
        type: Boolean,
        default: true
    },
    disabled: Boolean
})

const keyboard = ref<any>(null)
const keyboardWrapRef = ref(null)
const visible = ref(false)
const inputRef = ref()
const width = ref(1000)
if (props.layoutName == 'number') width.value = 300

const displayDefault = ref({
    '{bksp}': 'backspace',
    '{lock}': 'caps',
    '{enter}': 'enter',
    '{tab}': 'tab',
    '{shift}': 'shift',
    '{change}': 'en',
    '{space}': 'space',
    '{clear}': 'clear',
    '{close}': 'close',
    '{arrowleft}': '←',
    '{arrowright}': '→'
})

const open = () => {
    if (visible.value) return
    inputRef.value.focus()
    emits('focus')
    visible.value = true
}

const focusInput = () => {
    if (props.disabled) return
    if (visible.value) return
    emits('focus')
    if (props.isOpen) visible.value = true
}

const lang: any = {
    'zh-cn': {
        // 默认布局
        default: [
            '` 1 2 3 4 5 6 7 8 9 0 - = {bksp}',
            '{tab} q w e r t y u i o p [ ] \\',
            "{lock} a s d f g h j k l ; ' {enter}",
            '{change} z x c v b n m , . / {clear}',
            '{arrowleft} {arrowright} {space} {close}'
        ],
        // 大小写
        shift: [
            '~ ! @ # $ % ^ & * ( ) _ + {bksp}',
            '{tab} Q W E R T Y U I O P { } |',
            '{lock} A S D F G H J K L : " {enter}',
            '{change} Z X C V B N M < > ? {clear}',
            '{arrowleft} {arrowright} {space} {close}'
        ]
    },
    th: {
        default: [
            '\u005F \u0E45 \u002F \u002D \u0E20 \u0E16 \u0E38 \u0E36 \u0E04 \u0E15 \u0E08 \u0E02 \u0E0A {bksp}',
            '{tab} \u0E46 \u0E44 \u0E33 \u0E1E \u0E30 \u0E31 \u0E35 \u0E23 \u0E19 \u0E22 \u0E1A \u0E25 \u0E03',
            '{lock} \u0E1F \u0E2B \u0E01 \u0E14 \u0E40 \u0E49 \u0E48 \u0E32 \u0E2A \u0E27 \u0E07 {enter}',
            '{shift} \u0E1C \u0E1B \u0E41 \u0E2D \u0E34 \u0E37 \u0E17 \u0E21 \u0E43 \u0E1D {clear}',
            '{arrowleft} {arrowright} {space} {close}'
        ],
        shift: [
            '% + \u0E51 \u0E52 \u0E53 \u0E54 \u0E39 \u0E3F \u0E55 \u0E56 \u0E57 \u0E58 \u0E59 {bksp}',
            '{tab} \u0E50 \u0022 \u0E0E \u0E11 \u0E18 \u0E4D \u0E4A \u0E13 \u0E2F \u0E0D \u0E10 \u002C \u0E05',
            '{lock} \u0E24 \u0E06 \u0E0F \u0E42 \u0E0C \u0E47 \u0E4B \u0E29 \u0E28 \u0E0B \u002E {enter}',
            '{shift} ( ) \u0E09 \u0E2E \u0E3A \u0E4C \u003F \u0E12 \u0E2C \u0E26 {clear}',
            '{arrowleft} {arrowright} {space} {close}'
        ]
    }
}

const keyboardInit = () => {
    let keyboardLayout = {
        // 数字布局
        number: ['7 8 9', '4 5 6', '1 2 3', '. 0 {bksp}', '{arrowleft} {arrowright} {clear} {close}'],
        ...lang['zh-cn']
    }

    // if (lang[useSession('lang').value]) {
    //     keyboardLayout = { ...lang[useSession('lang').value], ...keyboardLayout }
    // }
    keyboard.value = new Keyboard('simple-keyboard', {
        onChange: onChange,
        onKeyPress: onKeyPress,
        onInit: onInit,
        layout: keyboardLayout,
        layoutName: props.layoutName,
        display: displayDefault.value
        // theme: 'hg-theme-default init-keyboard' // 添加自定义class处理清空逻辑
    })
}

const onInit = (keyboard: any) => {
    keyboard.setInput(String(model.value || ''))
    keyboard.setCaretPosition(inputRef.value?.ref.selectionEnd)
    document.addEventListener('click', handlePopClose)
}
const onChange = (input: any) => {
    model.value = input
    emits('onChange', input)
}

const onKeyPress = (button: any) => {
    if (button === '{lock}') return handleLock()
    if (button === '{change}') return handleChange()
    if (button === '{clear}') return handleClear()
    if (button === '{enter}') return handleEnter()
    if (button === '{close}') return close()
    if (button === '{arrowleft}') return handleArrow(0)
    if (button === '{arrowright}') return handleArrow(1)
}
const handleLock = () => {
    let currentLayout = keyboard.value.options.layoutName
    let shiftToggle = currentLayout === 'default' ? 'shift' : 'default'
    keyboard.value.setOptions({
        layoutName: shiftToggle
    })
}
const handleChange = () => {
    let layoutCandidates = keyboard.value.options.layoutCandidates
    // 切换中英文输入法
    if (layoutCandidates != null && layoutCandidates != undefined) {
        displayDefault.value['{change}'] = 'en'
        keyboard.value.setOptions({
            layoutName: 'default',
            layoutCandidates: null,
            display: displayDefault.value
        })
    } else {
        displayDefault.value['{change}'] = 'cn'
        keyboard.value.setOptions({
            layoutName: 'default',
            layoutCandidates: (layout as any)?.layoutCandidates,
            display: displayDefault.value
        })
    }
}
const handleClear = () => {
    keyboard.value.clearInput()
    model.value = ''
}
const handleEnter = () => {
    emits('enter')
}
const close = () => {
    if (props.layoutName == 'number') {
        // 处理精度
        model.value = model.value?.replace(new RegExp(`(\\d+)\\.(\\d{${props.precision}}).*$`), '$1.$2').replace(/\.$/, '')
    }
    document.removeEventListener('click', handlePopClose)
    visible.value = false
    emits('close')
}
const handleArrow = (num: number) => {
    // 处理左右箭头下标位置
    const index = keyboard.value.getCaretPositionEnd()
    if (num == 0 && index - 1 >= 0) {
        keyboard.value.setCaretPosition(index - 1)
    } else if (num == 1 && index + 1 <= (model.value?.length || 0)) {
        keyboard.value.setCaretPosition(index + 1)
    }
}

const handlePopClose = (e: any) => {
    // 虚拟键盘区域 输入框区域 中文选项区域
    if (
        (e.target as Element).closest('.keyboard-popper') ||
        (e.target as Element).closest('.keyboard-wrap') == keyboardWrapRef.value ||
        /hg-candidate-box/.test(e.target.className)
    ) {
        const index = keyboard.value.getCaretPositionEnd()
        inputRef.value.ref.selectionStart = inputRef.value.ref.selectionEnd = index
        inputRef.value.focus()
    } else {
        close()
    }
}

onUnmounted(() => {
    // 某些情况下未触发动画关闭时销毁事件。此处销毁做后备处理
    document.removeEventListener('click', handlePopClose)
})

defineExpose({ inputRef, visible, open, close, keyboardInit })
</script>

<style scoped>
.keyboard-wrap {
    width: 100%;
}
</style>

<style>
.hg-theme-default .hg-button.hg-button-arrowleft,
.hg-theme-default .hg-button.hg-button-arrowright {
    max-width: 70px;
}

.hg-theme-default .hg-button.hg-button-close {
    max-width: 100px;
}

.hg-layout-number .hg-button.hg-button-close {
    max-width: none;
}

.hg-layout-number .hg-button.hg-button-bksp {
    max-width: 92px;
}
</style>
