<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="roleSelf" :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
          ref="treeRef"
          show-checkbox
          node-key="code"
          :data="myTreeData || []"
          :props="treeProps"
          :filter-node-method="filterTree"
          :render-content="renderContent"
          @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 { cloneDeep } from 'lodash'
import { ROLE_BUTTON_CODES } from '@/constants/app'
import type { ExtractApiResponse } from '@/api/api'

type MenuItem = MainLayoutStore.MenuItem

type MenuItemWithId = MenuItem & { id: number }
function createNum(m: number, n: number) {
  return Math.floor(Math.random() * (m - n)) + n
}
const ROLE_OPTION = ref<any[]>([])
useFetch('getRoleList')
  .fetch()
  .then((res: any) => {
    ROLE_OPTION.value = res.map((item: any) => {
      return {
        value: item.code,
        label: item.roleName,
      }
    })
  })
const props = defineProps<{ role: ROLE }>()

const mainLayoutStore = useMainLayoutStore()

const roleSelf = 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')

const getTreeList = (oldDataList: any[], sortField = false): any[] => {
  if (!Array.isArray(oldDataList)) {
    throw new TypeError(`${oldDataList}不是数组`)
  }
  const dataList: any[] = cloneDeep(oldDataList)
  // 第一次是将全部的permissionId作为对象的key重组成一个对象
  const formatObj: any = dataList.reduce((pre, cur) => {
    return { ...pre, [cur['code']]: cur }
  }, {})
  // 排序
  const sortArray = sortField ? dataList.sort((a: any, b: any) => a['sort'] - b['sort']) : dataList
  const formatArray = sortArray.reduce((arr: any[], cur: any) => {
    const pCode = cur.parentCode ? cur.parentCode : '0'
    const parent = formatObj[pCode]
    if (parent) {
      parent.children ? parent.children.push(cur) : (parent.children = [cur])
    } else {
      arr.push(cur)
    }
    return arr
  }, [])
  return formatArray
}

watch(
  roleSelf,
  () => {
    roleSelf.value && getPrivilege({ role: roleSelf.value })
  },
  { immediate: true }
)
const filterTree = (value: string, data: any) => {
  return !data.originCode
}
const myTreeData = ref<any[]>([])
const treeProps = {
  label: 'name',
}
watch(myTreeData, () => {
  nextTick(() => {
    treeRef?.value?.filter('')
  })
})
const renderContent = (h: any, { node, data, store }: any) => {
  if (data.originCode) {
    return h(
      'span',
      {
        class: 'custom-tree-node',
      },
      h('span', { class: 'is-page' }, '页面')
    )
  }
  if (ROLE_BUTTON_CODES.includes(data.code)) {
    return h(
      'span',
      {
        class: 'custom-tree-node',
      },
      h('span', null, data.name),
      h('span', { class: 'is-btn' }, '按钮')
    )
  }
  return data.name
}

const getPCodes = (treeData: any, pCodes: any = []) => {
  for (let i = 0; i < treeData.length; i++) {
    let item: any = treeData[i]
    if (item.children && item.children.length) {
      pCodes.push(item.code)
      getPCodes(item.children, pCodes)
    }
  }
  return pCodes
}
const newFlatArr = ref<any[]>([])
watch(privilege, () => {
  let data = cloneDeep(privilege.value || [])
  data.forEach((item: any) => {
    if (ROLE_BUTTON_CODES.includes(item.code)) {
      item.type = 'button'
    }
  })
  let hasPermBtnPageNodes: any[] = []
  for (let i = 0; i < data.length; i++) {
    let node = data[i]
    if (ROLE_BUTTON_CODES.includes(node.code)) {
      let pNode: any = data.find((v: any) => v.code == node.parentCode) || {}
      if (!hasPermBtnPageNodes.find((v: any) => v.code == pNode.code + '_in_page')) {
        let id = createNum(-100000, -10000)
        hasPermBtnPageNodes.push(
          Object.assign({}, node, {
            code: pNode.code + '_in_page',
            name: '页面',
            hasPrivilege: !!pNode.hasPrivilege,
            originCode: node.code,
            type: 'page',
          })
        )
      }
    }
  }

  let concatData = [...hasPermBtnPageNodes, ...data]
  newFlatArr.value = cloneDeep(concatData)
  let treeData = getTreeList(concatData)
  myTreeData.value = treeData

  let pCodes = getPCodes(treeData)

  nextTick(() => {
    treeRef?.value?.setCheckedKeys(
      newFlatArr.value?.filter((d) => d.hasPrivilege && pCodes.indexOf(d.code) == '-1')?.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 = (a: any, b: any) => {
  let resultKeys: any = treeRef?.value?.getCheckedKeys(true)
  if (a.type == 'page') {
    let underPageBtnKeys: any[] = []
    if (!b) {
      for (let i = 0; i < newFlatArr.value.length; i++) {
        let item = newFlatArr.value[i]
        if (item.parentCode == a.parentCode && item.type === 'button') {
          underPageBtnKeys.push(item.code)
        }
      }
      resultKeys = resultKeys?.filter((k: any) => !underPageBtnKeys.includes(k))
      treeRef?.value?.setCheckedKeys(resultKeys)
    }
  }
  if (a.type == 'button') {
    if (!!b) {
      let page = newFlatArr.value.find((item: any) => item.type === 'page' && item.parentCode == a.parentCode)

      if (!resultKeys?.includes(page.code)) {
        treeRef?.value?.setCheckedKeys([...resultKeys, page.code])
      }
    }
  }
  setTimeout(() => {
    checkedMenus.value = (treeRef?.value?.getCheckedNodes() as MenuItemWithId[]) || []
  }, 1)
}

/** 保存 */
const onSubmit = async () => {
  try {
    const checkedNodes = treeRef?.value?.getCheckedNodes() || []
    const checkedHalfNodes = treeRef?.value?.getHalfCheckedNodes() || []
    const privilegeIds = checkedNodes
      .concat(checkedHalfNodes)
      .map((d) => d.code)
      .filter((code) => code != '-1')

    await setPrivilege({ role: roleSelf.value, privilegeCodes: privilegeIds })
    ElMessage.success('保存成功')
  } catch (error) {
    console.error(error)
  }
}
</script>

<style scoped lang="scss">
.privilege-tree {
  width: 660px;
  min-height: 320px;
  :deep(.custom-tree-node) {
    .is-page,
    .is-btn {
      padding: 0 5px;
      font-size: 8px;
      border-radius: 4px;
      background: #67c23a;
      color: #fff;
    }
    .is-btn {
      margin-left: 8px;
    }
  }
}
</style>
