<template>
  <div class="p-base full">
    <div class="flex direction-column p-t-base p-b-base p-l-large fill-blank">
      <div class="flex items-center">
        <span class="m-r-base">角色</span>
        <base-select v-model="role" :options="ROLE_OPTION"></base-select>
        <el-button class="m-l-base" type="primary" :loading="loading" @click="onSubmit">保存</el-button>
      </div>
      <div class="flex-1 p-base m-t-large fill-lighter full-scroll-y-auto privilege-tree">
        <el-tree ref="treeRef" show-checkbox node-key="index" :data="menuTree || []" @check-change="onCheckChange">
        </el-tree>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts" name="RoleSetting">
/** 角色权限管理 */
import { computed, nextTick, ref, watch } from 'vue'
import { ElButton, ElTree, ElMessage } from 'element-plus'
import { ROLE_OPTION } from '@/constants/dicts'
import useFetch from '@/hooks/useFetch'
import useMainLayoutStore from '@/store/layout'
import BaseSelect from '@/components/element/BaseSelect.vue'

import type { ExtractApiResponse } from '@/api/api'

type MenuItem = MainLayoutStore.MenuItem

type MenuItemWithId = MenuItem & { id: number }

const props = defineProps<{ role: ROLE }>()

const mainLayoutStore = useMainLayoutStore()

const role = ref<ROLE>(props.role)

const treeRef = ref<InstanceType<typeof ElTree>>()

const checkedMenus = ref<MenuItemWithId[]>([])

const { fetch: getPrivilege, result: privilege } = useFetch('getRolePrivilege')

const { fetch: setPrivilege, loading } = useFetch('setRolePrivilege')

watch(
  role,
  () => {
    role.value && getPrivilege({ role: role.value })
  },
  { immediate: true }
)

watch(privilege, () => {
  nextTick(() => {
    treeRef?.value?.setCheckedKeys(privilege?.value?.filter((d) => d.hasPrivilege)?.map((d) => d.code))
  })
})

function filterPrivilege(
  item: MenuItem,
  privilege: ExtractApiResponse<'getRolePrivilege'>
): MenuItemWithId | undefined {
  const privilegeItem = privilege.find((d) => item.index === d.code)
  if (privilegeItem) {
    return {
      ...item,
      id: privilegeItem.id,
      children: item.children?.map((child) => filterPrivilege(child, privilege)).filter((d) => !!d) as MenuItemWithId[],
    }
  }
}

const menuTree = computed(() => {
  return mainLayoutStore.menuList?.reduce((menus, menu) => {
    return menus.concat(filterPrivilege(menu, privilege.value || []) || [])
  }, [] as MenuItem[])
})

const onCheckChange = () => {
  checkedMenus.value = (treeRef?.value?.getCheckedNodes() as MenuItemWithId[]) || []
}

/** 保存 */
const onSubmit = async () => {
  try {
    const checkedNodes = treeRef?.value?.getCheckedNodes() || []
    const checkedHalfNodes = treeRef?.value?.getHalfCheckedNodes() || []
    const privilegeIds = checkedNodes.concat(checkedHalfNodes).map((d) => d.id)
    await setPrivilege({ role: role.value, privilegeIds })
    ElMessage.success('保存成功')
  } catch (error) {
    console.error(error)
  }
}
</script>

<style scoped lang="scss">
.privilege-tree {
  width: 660px;
  min-height: 320px;
}
</style>
