<script setup lang="ts">
import { StrAnyObj, StrAnyObjArr } from '@/typings'
import { editMenuScopeApi, getMenuScopeApi } from '@/api/system/role'
import { CheckboxValueType } from 'element-plus'

const dialogTitle = ref<string>('')
const dialogVisible = ref<boolean>(false)
const roleId = ref<number>()

// 菜单树数据
const treeData = ref<StrAnyObjArr>([])
// 父级子集map
const dataMap = ref<Map<string, StrAnyObj>>(new Map<string, StrAnyObjArr>())
// 菜单选中
const selectId = ref<Set<string>>(new Set<string>())

function handleTreeData(data: StrAnyObj) {
  if (data.type == 2) {
    if (data?.children?.length > 0) {
      data?.children?.forEach((item: StrAnyObj) => dataMap.value.set(item.id, item))
      data.children = [{ type: 3, buttonList: data.children }]
    }
  } else {
    data.children?.forEach((item: StrAnyObj) => {
      dataMap.value.set(item.id, item)
      handleTreeData(item)
    })
  }
}

function open(data: StrAnyObj) {
  dialogVisible.value = true
  dialogTitle.value = `【${data.name}】分配菜单权限`
  roleId.value = data.id
  getMenuScopeApi({ id: roleId.value }).then((resp) => {
    resp.menuTree.forEach((item) => {
      dataMap.value.set(item.id, item)
      handleTreeData(item)
    })
    treeData.value = resp.menuTree

    resp.menuIdList.forEach((item) => {
      selectId.value.add(item)
    })
  })
}

function changeCheckbox(flag: boolean, row: StrAnyObj) {
  flag ? selectId.value.add(row.id) : selectId.value.delete(row.id)
  flag ? selectParent(row) : cancelParent(row)

  switch (row.type) {
    case 1:
      row.children?.forEach((item: StrAnyObj) => {
        changeCheckbox(flag, item)
      })
      break
    case 2:
      row.children?.[0]?.buttonList?.forEach((item: StrAnyObj) => {
        changeCheckbox(flag, item)
      })
      break
  }
}

function selectParent(row?: StrAnyObj) {
  if (row?.parentId && row.parentId != 0) {
    selectId.value.add(row.parentId)
    selectParent(dataMap.value.get(row.parentId))
  }
}

function cancelParent(row?: StrAnyObj) {
  if (!row || row.type === 3 || !row.parentId) {
    return
  }

  const children = dataMap.value.get(row.parentId)?.children

  if (!children) {
    return
  }

  let deleteFlag = true
  for (const item of children) {
    if (selectId.value.has(item.id)) {
      deleteFlag = false
      break
    }
  }
  if (deleteFlag) {
    selectId.value.delete(row.parentId)
    cancelParent(dataMap.value.get(row.parentId))
  }
}

function formSubmit() {
  editMenuScopeApi({ id: roleId.value, selectMenuIdList: Array.from(selectId.value) }).then(() => {
    ElMessage.success('修改成功')
    dialogVisible.value = false
  })
}

function formClosed() {
  treeData.value = []
  dataMap.value = new Map<string, StrAnyObjArr>()
  selectId.value = new Set<string>()
}

defineExpose({ open })
</script>

<template>
  <a-dialog
    v-model="dialogVisible"
    :title="dialogTitle"
    width="1000px"
    @submit="formSubmit"
    @closed="formClosed"
  >
    <el-tree :data="treeData" node-key="id" default-expand-all :expand-on-click-node="false">
      <template #default="{ data }">
        <div>
          <template v-if="data.type === 3">
            <el-checkbox
              v-for="item in data.buttonList"
              :key="item.id"
              :model-value="selectId.has(item.id)"
              :label="item.title"
              size="large"
              @change="(flag: CheckboxValueType) => changeCheckbox(flag as boolean, item)"
            />
          </template>
          <template v-else>
            <el-checkbox
              :key="data.id"
              :model-value="selectId.has(data.id)"
              :label="data.title"
              size="large"
              @change="(flag: CheckboxValueType) => changeCheckbox(flag as boolean, data)"
            />
          </template>
        </div>
      </template>
    </el-tree>
  </a-dialog>
</template>
