<template>
  <ElDrawer ref="elDrawerRef" v-model="drawerVisible" :title="drawerProps.title" v-bind="$attrs" destroy-on-close>
    <template #header="scope">
      <slot name="header" v-bind="scope">
        <div style="display: flex">
          <slot name="title">
            <span style="flex: 1">{{ drawerProps.title }}</span>
          </slot>
        </div>
      </slot>
    </template>

    <el-table :data="mergeData" :span-method="objectSpanMethod" border style="width: 100%; margin-top: 20px">
      <el-table-column prop="moduleName" width="180">
        <template #header>
          <el-checkbox label="权限模块" @change="handleChange"></el-checkbox>
        </template>
        <template #default="{ row }">
          <div>
            <el-checkbox v-model="row.parentCheck" :label="row.moduleName" @change="handleParentCheck(row)"></el-checkbox>
          </div>
        </template>
      </el-table-column>
      <el-table-column prop="code">
        <template #header>
          <el-checkbox label="权限点" @change="handleChange"></el-checkbox>
        </template>
        <template #default="{ row }">
          <div>
            <el-checkbox v-model="row.itemCheck" :label="row.code" @change="handleItemCheck(row)"></el-checkbox>
          </div>
        </template>
      </el-table-column>

      <el-table-column prop="name" label="名称" />
    </el-table>
    <template #footer>
      <slot name="footer">
        <ElButton @click="drawerVisible = false">取 消</ElButton>
        <ElButton type="primary" @click="handleConfirm()">确 定</ElButton>
      </slot>
    </template>
  </ElDrawer>
</template>

<script setup lang="ts" name="PermissionsDrawer">
import { PermissionsVO } from '@/api/interface/system/permissions'
import { RoleVO } from '@/api/interface/system/role'
import RoleApi from '@/api/module/system/role'
import { ResultEnum } from '@/enums/HttpEnum'

interface EcoDrawerProps {
  api?: (params: any) => Promise<any> // 调用接口
  title: string // 顶部标题
  row: Partial<RoleVO>
  getTableList?: () => void
}

interface MergeDataProps extends PermissionsVO {
  parentCheck: boolean
  itemCheck: boolean
}
const getSpanArr = (data: MergeDataProps[], prop: keyof MergeDataProps) => {
  const spanArr: { first: number; count: number }[] = []
  let pos = 0

  for (let i = 0; i < data.length; i++) {
    if (i === 0) {
      spanArr.push({ first: 0, count: 1 })
      pos = 0
    } else {
      if (data[i][prop] === data[i - 1][prop]) {
        spanArr[pos].count++
        spanArr.push({ first: -1, count: 0 })
      } else {
        spanArr.push({ first: i, count: 1 })
        pos = i
      }
    }
  }

  return spanArr
}
const nameSpanArr = computed(() => getSpanArr(mergeData.value, 'moduleName'))

const objectSpanMethod = ({ row, column, rowIndex, columnIndex }: { row: MergeDataProps; column: any; rowIndex: number; columnIndex: number }) => {
  if (column.property === 'moduleName') {
    const span = nameSpanArr.value[rowIndex]
    if (span.first === rowIndex) {
      return {
        rowspan: span.count,
        colspan: 1
      }
    } else {
      return {
        rowspan: 0,
        colspan: 0
      }
    }
  }
}

// 获取选中的 address IDs
const selectedPermIds = computed(() => {
  return mergeData.value.filter(item => item.itemCheck).map(item => item.id)
})

// 处理 moduleName 复选框变化
const handleParentCheck = (row: MergeDataProps) => {
  const itemRows = mergeData.value.filter(item => item.moduleName === row.moduleName)
  itemRows.forEach(item => {
    item.itemCheck = row.parentCheck
  })
}

const handleChange = (val: boolean) => {
  mergeData.value.forEach(item => {
    item.parentCheck = val
    item.itemCheck = val
  })
}

// 处理 code 复选框变化
const handleItemCheck = (row: MergeDataProps) => {
  const sameItemRows = mergeData.value.filter(item => item.moduleName === row.moduleName)
  const parentSelected = sameItemRows.every(item => item.itemCheck)

  // 更新对应 moduleName 的选中状态
  sameItemRows.forEach(item => {
    item.parentCheck = parentSelected
  })
}

const allPermissions = ref<PermissionsVO[]>([])
const hasPermissions = ref<string[]>([])
const mergeData = ref<MergeDataProps[]>([])

const drawerVisible = ref(false)
const drawerProps = ref<EcoDrawerProps>({
  title: '',
  row: {}
})

// emit
const emit = defineEmits(['submit'])

// 接收父组件传过来的参数
const acceptParams = (params: EcoDrawerProps) => {
  drawerProps.value = params
  drawerVisible.value = true
  getPermissions(params.row.roleId || '')
}

/**
 * 获取权限信息
 * @param roleId
 */
const getPermissions = (roleId: string) => {
  if (!roleId) return
  RoleApi.getPermissions(roleId).then(res => {
    allPermissions.value = res.data.allPermissions
    hasPermissions.value = res.data.hasPermissions
    handelAllPermissions(allPermissions.value, hasPermissions.value)
  })
}

const handelAllPermissions = (allPerms: PermissionsVO[], hasPerms: string[]) => {
  const itemMap = ref(new Map<string, boolean>())
  const parentMapCount = ref(new Map<string, number>())
  const itemMapCount = ref(new Map<string, number>())
  const nameCount = ref(0)
  const count = ref(0)
  mergeData.value = allPerms.map(item => {
    if (!parentMapCount.value.get(item.moduleName)) {
      nameCount.value = 0
    }
    parentMapCount.value.set(item.moduleName, ++nameCount.value)
    if (hasPerms.length > 0) {
      hasPerms.forEach(permId => {
        if (item.id === permId) {
          itemMap.value.set(item.id, true)
          if (!itemMapCount.value.get(item.moduleName)) {
            count.value = 0
          }
          itemMapCount.value.set(item.moduleName, ++count.value)
        }
      })
    }
    return {
      ...item,
      parentCheck: false,
      itemCheck: itemMap.value.get(item.id) || false
    }
  })
  mergeData.value.forEach(item => {
    item.parentCheck = parentMapCount.value.get(item.moduleName) === itemMapCount.value.get(item.moduleName)
  })
}

const handleConfirm = async () => {
  try {
    const { code } = await drawerProps.value.api!({ roleId: drawerProps.value.row.roleId, permIds: selectedPermIds.value })
    if (code == ResultEnum.SUCCESS) {
      ElMessage.success({ message: `${drawerProps.value.title}成功！` })
      drawerProps.value.getTableList!()
      emit('submit')
      drawerVisible.value = false
    }
  } catch (error) {
    console.log(error)
  }
}

defineExpose({
  acceptParams
})
</script>

<style scoped lang="scss"></style>
