<script setup lang="ts">
import type { DropdownInstance } from 'element-plus'
import type { IconDropdownItem } from '@/types/dataAnalysis'

import { onMounted, ref, reactive, watch } from 'vue'
import { initLoadResouce } from '@/utils/resource'
import { useCommonStore } from '@/stores/useCommon'

const { selectInfo, tempMultipleChioce, saveSelectInfo, saveTempMultipleChioce } = useCommonStore()

interface DropdownInfo {
  isRadio?: boolean // 是否是单选
  slectInfo: Array<IconDropdownItem>
}

// props
const props = withDefaults(defineProps<DropdownInfo>(), {
  isRadio: true
})

/**
 * @description:  初始化选择信息
 * @return {*}
 */
const selectBaseInfo = reactive<Array<IconDropdownItem>>(
  JSON.parse(JSON.stringify(props.slectInfo))
)

// 判断是不是通过确认框关闭的。主要服务于多选的情况
// 原理是因为点击确认关闭的话，确认事件会先触发，然后再触发关闭事件
// 由此来去判断是否需要把多选框的信息恢复
const isConfimClose = ref<Boolean>(false)

// emits
const emits = defineEmits(['changePf'])

// 下拉框
const dropDownRef = ref<DropdownInstance>()

// 资源的加载路径
const resourceInfo: Record<string, string> = selectBaseInfo.reduce(
  (acc, item) => {
    acc[item.value] = item.icon
    return acc
  },
  {} as Record<string, string>
)

// 使用blob的资源路径信息
const blobUrlInfo = reactive<Record<string, string>>({})

// 备份信息
const backupInfo = reactive<Array<IconDropdownItem>>([])

/**
 * @description: 确认选择
 * 这里主要用于多选的情况使用，对于单选，即使点击确认按钮也不会有二次请求，因为seleinfo没有改变
 * @return {*}
 */
const confirmSelect = () => {
  isConfimClose.value = true // 通过确认事件关闭
  Object.assign(backupInfo, JSON.parse(JSON.stringify(selectBaseInfo)))
  dropDownRef.value?.handleClose()

  if (props.isRadio) return

  // 去把state的数据更新一下
  tempMultipleChioce.pf = selectBaseInfo.filter((item) => item.isSelected).map((item) => item.value)

  saveTempMultipleChioce() // 保存到本地
}

/**
 * @description: 取消选择，当取消选择后，需要恢复到原来的状态
 * @return {*}
 */
const cancleSelect = () => {
  dropDownRef.value?.handleClose()
  Object.assign(selectBaseInfo, backupInfo)
}

/**
 * @description: 下拉框出现与消失的处理
 * @param {*} state 展示状态，值为true或者false，代表打开或者关闭
 * @return {*}
 */
const dropdownVis = (state: boolean) => {
  if (state) {
    // 打开的时候，需要备份一下当前选择
    Object.assign(backupInfo, JSON.parse(JSON.stringify(selectBaseInfo)))
  } else {
    // 关闭的时候，如果一个都没有选中，那么就需要把备份的信息恢复回去
    // 这里只针对于多选情况，因为单选的逻辑中不存在一个都没有选中的情况，因为无法取消已经选中
    // 而多选的情况下，因为即使可以取消，也不会立即改变selectInfo中的信息，只有点击了确认按钮才会改变，所以这里只需要恢复props的selectinfo就行了

    // 不是点击确认按钮关闭的多选框，且是多选按钮，也需要恢复
    if (!selectBaseInfo.find((item) => item.isSelected) || (!isConfimClose.value && !props.isRadio))
      Object.assign(selectBaseInfo, backupInfo)
    if (isConfimClose.value) isConfimClose.value = false // 把状态重置
  }
}

/**
 * @description: 选择事件，当目前可以选择或者是这个选项已经被选中的时候，就允许改变他的状态
 * @param {*} item  当前的选项信息
 * @return {*}
 */
const selectPf = (item: any) => {
  if (props.isRadio) {
    selectInfo.pf = []
    selectInfo.pf.push(item.value)

    saveSelectInfo() // 选择之后保存到本地一次
  } else {
    // 多选就取反就行
    item.isSelected = !item.isSelected
  }
}

/**
 * @description: 同步selectinfo的信息到页面上
 * @return {*}
 */
const syncSelectInfo = () => {
  selectBaseInfo.forEach((item) => {
    item.isSelected = selectInfo.pf.includes(item.value)
  })
}

/**
 * @description: 同步tempMultipleChioce的信息到页面上
 * @return {*}
 */
const syncTempMultipleChioce = () => {
  selectBaseInfo.forEach((item) => {
    item.isSelected = tempMultipleChioce.pf.includes(item.value)
  })
}

/**
 * @description: 监听selectinfo的变化，然后同步到页面上
 * @return {*}
 */
const watchSelectPf = watch(
  () => selectInfo.pf,
  () => {
    syncSelectInfo()
  },
  { deep: true }
)

/**
 * @description:  监听tempMultipleChioce的变化，然后同步到页面上
 * @return {*}
 */
const watchTempMultipleChioce = watch(
  () => tempMultipleChioce.pf,
  () => {
    syncTempMultipleChioce()
  },
  { deep: true }
)

/**
 * @description: 根据本地保存的方案信息，去初始化selectinfo的信息
 * @return {*}
 */
const initSelectInfo = () => {
  if (props.isRadio) {
    watchTempMultipleChioce() // 如果是单选进来的，在这儿把多选的事件取消掉
    syncSelectInfo() // 同步一下数据
  } else {
    watchSelectPf() // 与上面同理
    syncTempMultipleChioce() // 同理
  }
}

// 去加载一下本地的信息
initSelectInfo()

onMounted(() => {
  // 去加载所有需要的资源

  initLoadResouce(resourceInfo).then((data) => {
    Object.assign(blobUrlInfo, data)
  })
})
</script>

<template>
  <div>
    <el-dropdown
      trigger="click"
      @visible-change="dropdownVis"
      :hide-on-click="props.isRadio"
      ref="dropDownRef"
    >
      <span class="displayBox">
        <div class="displayIcon">
          <span class="iconItem" v-for="item in selectBaseInfo">
            <el-image
              v-if="item.isSelected"
              style="width: 20px; height: 20px; margin-right: 5px"
              :src="blobUrlInfo[item.value]"
              :fit="'cover'"
            />
          </span>
        </div>

        <el-icon class="el-icon--right">
          <arrow-down />
        </el-icon>
      </span>
      <template #dropdown>
        <el-dropdown-menu>
          <el-dropdown-item
            v-for="item in selectBaseInfo"
            :key="item.value"
            :value="item.value"
            @click="selectPf(item)"
          >
            <el-image
              style="width: 20px; height: 20px; margin-right: 5px"
              :src="blobUrlInfo[item.value]"
              :fit="'cover'"
            />
            <!-- 禁用掉原生的点击事件，自己实现点击 -->
            <el-checkbox v-model="item.isSelected" size="small" @click.native.prevent="return" />
          </el-dropdown-item>
        </el-dropdown-menu>
        <span class="btnGroup">
          <el-button class="btnItem" size="small" type="primary" @click="confirmSelect"
            >确认</el-button
          >
          <el-button class="btnItem" size="small" @click="cancleSelect">取消</el-button>
        </span>
      </template>
    </el-dropdown>
  </div>
</template>

<style scoped>
.displayBox {
  display: flex;
  align-items: center;
}

.displayIcon {
  display: flex;
  align-items: center;
}

.btnGroup {
  display: flex;
  justify-content: center;
}
.btnItem {
  margin-right: 4px;
  margin-left: 4px;
}

.disabledSelect {
  cursor: not-allowed !important;
}
</style>
