<script setup lang="ts">
import 'simple-keyboard/build/css/index.css'

import Keyboard from 'simple-keyboard'
import layout from 'simple-keyboard-layouts/build/layouts/chinese.js'
import { useDeviceStore } from 'stores/deviceStore'
import { computed, onUnmounted, ref } from 'vue'

defineOptions({
  inheritAttrs: false,
})
const props = defineProps({
  layoutName: {
    type: String,
    default: 'default',
  },
  // 保留几位小数 layoutName为number时生效
  precision: {
    type: Number,
    default: 2,
  },
})
const emits = defineEmits(['onChange', 'enter', 'close', 'focus'])
const deviceStore = useDeviceStore()
const deviceType = computed(() => {
  return __DEVICE_TYPE__
})

const model = defineModel()
const keyboard = ref<any>(null)
const visible = ref(false)
const inputRef = ref()
const popoverRef = ref()
const entering = ref(false)
const width = ref(800)
if (props.layoutName === 'number')
  width.value = 300
const displayDefault = ref({
  '{bksp}': 'backspace',
  '{lock}': 'caps',
  '{enter}': '回车',
  '{tab}': 'tab',
  '{shift}': 'shift',
  '{change}': 'en',
  '{space}': 'space',
  '{clear}': '清空',
  '{close}': '关闭',
  '{arrowleft}': '←',
  '{arrowright}': '→',
})

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

const focusInput = (e: any) => {
  const rect = e.target.getBoundingClientRect()
  if (rect.top + window.scrollY > 800) {
    placement.value = 'top'
  }
  else {
    placement.value = 'bottom'
  }
  if (visible.value)
    return
  if (deviceType.value !== deviceStore.deviceTypeMap.LargeSpaceDM_B)
    visible.value = true
}
emits('focus')

// const blurInput = debounce(() => {
//  if (!entering.value) {
//    handleClose()
//  } else {
//    entering.value = false
//  }
// }, 100)

const blurInput = () => {
  setTimeout(() => {
    if (!entering.value) {
      handleClose()
    }
    else {
      entering.value = false
    }
  }, 100)
}

const afterEnter = () => {
  // 存在上一个实例时移除元素
  const prevKeyboard = document.querySelectorAll('.init-keyboard')
  if (prevKeyboard.length > 0)
    prevKeyboard[0]?.remove()
  keyboard.value = new Keyboard('simple-keyboard', {
    onChange,
    onKeyPress,
    onInit,
    layout: {
      // 默认布局
      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}',
      ],
      // 数字布局
      number: ['7 8 9', '4 5 6', '1 2 3', '. 0 {bksp}', '{arrowleft} {arrowright} {clear} {close}'],
    },
    layoutName: props.layoutName,
    display: displayDefault.value,
    theme: 'hg-theme-default init-keyboard', // 添加自定义class处理清空逻辑
  })
}

const beforeLeave = () => {
  visible.value = false
  entering.value = false
  inputRef.value.blur()
  displayDefault.value['{change}'] = 'en'
  document.removeEventListener('click', handlePopClose)
}

const onInit = (keyboard: any) => {
  keyboard.setInput(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 handleClose()
  if (button === '{arrowleft}')
    return handleArrow(0)
  if (button === '{arrowright}')
    return handleArrow(1)
}
const handleLock = () => {
  entering.value = true
  const currentLayout = keyboard.value.options.layoutName
  const shiftToggle = currentLayout === 'default' ? 'shift' : 'default'

  keyboard.value.setOptions({
    layoutName: shiftToggle,
  })
}
const handleChange = () => {
  entering.value = true
  const 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}'] = '中'
    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 handleClose = () => {
  if (props.layoutName === 'number') {
    // 处理精度
    // model.value = model.value?.replace(new RegExp(`(\\d+)\\.(\\d{${props.precision}}).*$`), '$1.$2').replace(/\.$/, '')
  }
  popoverRef.value.hide()
  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 === inputRef.value?.ref
    || /hg-candidate-box/.test(e.target.className)
  ) {
    entering.value = true
    const index = keyboard.value.getCaretPositionEnd()
    inputRef.value.ref.selectionStart = inputRef.value.ref.selectionEnd = index
    inputRef.value.focus()
  }
}

const close = () => {
  handleClose()
}

const placement = ref('bottom')

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

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

<template>
  <el-input
    ref="inputRef"
    v-model="model"
    v-bind="$attrs"
    @focus="focusInput"
    @blur="blurInput"
    @keyup.enter="handleEnter"
  >
    <template v-for="(item, index) in $slots" :key="index" #[index]>
      <slot :name="index" />
    </template>
  </el-input>

  <el-popover
    ref="popoverRef"
    :visible="visible"
    :virtual-ref="inputRef"
    virtual-triggering
    :width="width"
    :show-arrow="false"
    :hide-after="0"
    :placement="placement"
    popper-style="padding: 0px;color:#000"
    :persistent="false"
    popper-class="keyboard-popper"
    @after-enter="afterEnter"
    @before-leave="beforeLeave"
  >
    <div class="simple-keyboard" />
  </el-popover>
</template>

<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>
