<template>
  <div class="combo_grid">
    <el-popover placement="bottom"
                :width="tableConfig.width"
                trigger="manual"
                :visible="tableConfig.isShow">
      <template #reference>
        <el-input
            ref="inputRef"
            :placeholder="placeholder"
            @input="queryData"
            v-model="inputData"
            @focus="inputFocus"
            @click="clickInput"
            :disabled="props.disabled"
            @blur="inputBlur"
            @keydown.esc="tableConfig.isShow = false"
            @keydown.enter.prevent="keyEnter"
            @mousedown.stop
            @keydown.up.prevent="keyUp"
            @keydown.down.prevent="keyDown"
            @keydown.left.prevent="keyLeft"
            @keydown.right.prevent="keyRight"
            @clear="clear"
            :clearable="clearable"/>
      </template>
      <div class="table-container"
           @mousedown.prevent>
        <el-table :data="tempTableList"
                  ref="tableRef"
                  @row-click="clickRow">
          <el-table-column v-for="item in tableHeader"
                           :label="item.label"
                           show-overflow-tooltip
                           :prop="item.prop"
                           :width="item.width"/>
          <slot/>
        </el-table>
        <el-pagination
            small
            :pager-count="5"
            :total="tableData.total"
            :current-page="tableData.currentPage"
            :page-size="tableData.pageSize"
            @size-change="handleSizeChange"
            layout="total,prev, pager, next"
            @current-change="handleCurrentChange"/>
      </div>
    </el-popover>
  </div>

</template>

<script setup name='XcComboGrid'>
import {debounce} from "@/utils/debounce";

const props = defineProps({
  modelValue: {
    type: [String, Object],
  },
  // 如果绑定的是Object那么就需要写这个
  code: {
    type: String,
    default: 'code'
  },
  name: {
    type: String,
    default: 'name'
  },
  rowKey: {
    type: String,
    default: 'code'
  },
  currentKey: {
    type: String,
    default: null
  },
  clearable: {
    type: Boolean,
    default: false
  },
  queryDataFunc: {
    type: Function,
    default: null
  },
  tableHeader: {
    type: Array,
    default: [
      {label: '编码', prop: 'code', width: 120},
      {label: '名称', prop: 'name', width: 220},
    ]
  },
  placeholder: {
    type: String,
    default: '搜索（拼音、五笔、编码、名称）'
  },
  disabled: {
    type: Boolean,
    default: false
  },
  data: {
    type: Array,
    default: null
  }
})

const emit = defineEmits(['input', 'rowClick', 'clear', 'focus', 'blur'])

const placeholder = ref(props.placeholder)
const inputData = ref('')
const tableData = ref({
  list: [],
  currentPage: 1,
  pageSize: 5,
  total: 0,
})

const tableConfig = ref({
  isLoad: false,
  isShow: false,
  width: 0
})
const isFocus = ref(false)

const queryData = debounce((value) => {
  emit('input', value)
  tableConfig.value.isLoad = true
  if (props.queryDataFunc === null) return
  props.queryDataFunc(value).then((res) => {
    tableData.value.currentPage = 1
    tableConfig.value.isShow = true
    tableData.value.list = res
    tableData.value.total = tableData.value.list.length
    theNumberOfPages = Math.ceil(tableData.value.total / tableData.value.pageSize)
    currentIndex = 0
    rowAddClass()
  }).finally((res) => {
    tableConfig.value.isLoad = false
  })

}, 200)

let currentIndex = 0;

const tableRef = ref(null)

const keyUp = () => {
  if (tableConfig.value.isShow) {
    currentIndex--;
    if (currentIndex < 0) {
      currentIndex = tempTableList.value.length - 1
      keyLeft()
    }
    rowAddClass()
  }
}

const keyDown = () => {
  if (tableConfig.value.isShow) {
    currentIndex++;
    if (currentIndex > tempTableList.value.length - 1) {
      currentIndex = 0
      keyRight()
    }
    rowAddClass()
  }
}

const keyEnter = () => {
  if (tableConfig.value.isShow && tempTableList.value.length > 0) {
    clickRow(tempTableList.value[currentIndex])
  } else {
    clickInput()
  }
}

let theNumberOfPages = 0
const keyLeft = () => {
  if (!tableConfig.value.isShow) return
  if (tableData.value.currentPage - 1 < 1) {
    tableData.value.currentPage = theNumberOfPages
  } else {
    tableData.value.currentPage--
  }
  if (currentIndex > tempTableList.value.length) {
    currentIndex = 0
  }
}

const keyRight = () => {
  if (!tableConfig.value.isShow) return
  if (tableData.value.currentPage + 1 > theNumberOfPages) {
    tableData.value.currentPage = 1
  } else {
    tableData.value.currentPage++
  }
}

const rowAddClass = async () => {
  if (!tableConfig.value.isShow) {
    return
  }
  await nextTick()
  let row = tableRef.value.$el.querySelectorAll('.el-table__row')
  for (let i = 0; i < row.length; i++) {
    let item = row[i]
    item.classList.remove('selected')
    if (i === currentIndex) {
      item.classList.add('selected')
    }
  }
}

const inputFocus = () => {
  emit('focus')
  isFocus.value = true
  if (isObj) {
    placeholder.value = props.modelValue[props.name]
  } else {
    placeholder.value = props.modelValue;
  }
  inputData.value = ''
}

const clickInput = () => {
  if (isObj) {
    placeholder.value = props.modelValue[props.name]
  } else {
    placeholder.value = props.modelValue;
  }
  inputData.value = ''
  tableConfig.value.isShow = !tableConfig.value.isShow
}

const clear = () => {
  focus()
  if (isObj) {
    props.modelValue[props.code] = null
    props.modelValue[props.name] = null
  } else {
    props.modelValue = null
  }
  emit('clear');
}

const highlightRow = async () => {
  await nextTick()
  if (!isObj && props.currentKey === null) {
    return;
  }
  let row = tableRef.value.$el.querySelectorAll('.el-table__row')
  for (let i = 0; i < tempTableList.value.length; i++) {
    let item = tempTableList.value[i]
    row[i].classList.remove('current_key')
    if (isObj) {
      if (item[props.rowKey] === props.modelValue[props.code]) {
        row[i].classList.add('current_key');
      }
    } else {
      if (item[props.rowKey] === props.currentKey) {
        row[i].classList.add('current_key');
      }
    }
  }
}

const inputBlur = () => {
  emit('blur')
  isFocus.value = false
  if (isObj) {
    inputData.value = props.modelValue[props.name]
  } else {
    inputData.value = props.modelValue;
  }
  if (!inputData.value) {
    placeholder.value = props.placeholder
  }
  tableConfig.value.isShow = false
}

const tempTableList = computed(() => {
  highlightRow()
  return tableData.value.list.slice((tableData.value.currentPage - 1) * tableData.value.pageSize, tableData.value.currentPage * tableData.value.pageSize);
})

const handleSizeChange = (val) => {
  tableData.value.pageSize = val
}

const handleCurrentChange = async (val) => {
  tableData.value.currentPage = val
}

const clickRow = async (row) => {
  if (isObj) {
    props.modelValue[props.code] = row['code']
    props.modelValue[props.name] = row['name']
  }
  await highlightRow()
  emit('rowClick', row)
  tableConfig.value.isShow = false
}

const inputRef = ref()
const focus = () => {
  inputRef.value.focus()
}
const blur = () => {
  inputRef.value.blur()
};

const isObj = typeof props.modelValue === 'object'
onMounted(() => {
  rowAddClass()
  if (isObj) {
    watch(() => props.modelValue[props.code], () => {
      inputData.value = props.modelValue[props.name]
      highlightRow()
    }, {immediate: true, deep: true})
  } else {
    watch(() => props.modelValue, () => {
      inputData.value = props.modelValue
      highlightRow()
    }, {immediate: true, deep: true})
  }
  if (props.data !== null) {
    watch(() => props.data, () => {
      if (isFocus.value) {
        tableConfig.value.isShow = true
      }
      tableData.value.list = props.data;
      tableData.value.total = tableData.value.list.length
      tableData.value.currentPage = 1
    }, {immediate: true, deep: true})
  }

})

defineExpose({
  focus,
  blur
})

</script>

<style scoped lang="scss">
.combo_grid {
  display: inline-block;
}

.table-container {
  :deep(.el-table) {
    tbody tr:hover > td {
      background-color: unset !important
    }

    .selected {
      background-color: #6faffa;
      color: white;
    }

    .current_key {
      background-color: #ffff00b8;
      color: #000;
    }

  }
}
</style>
