<template>
  <!-- 增加弹窗宽度从800px到1200px -->
  <Dialog v-model="dialogVisible" title="课程数据权限" width="1200">
    <el-form ref="formRef" v-loading="formLoading" :model="formData" label-width="80px">
      <!-- 使用el-row和el-col让角色名称和角色标识在一排显示 -->
      <el-row :gutter="20">
        <el-col :span="12">
          <el-form-item label="角色名称">
            <el-tag>{{ formData.name }}</el-tag>
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <el-form-item label="角色标识">
            <el-tag>{{ formData.code }}</el-tag>
          </el-form-item>
        </el-col>
      </el-row>

      <el-divider content-position="left">课程数据权限</el-divider>
      <br/>

      <el-row :gutter="20">
        <el-col :span="12">
          <!-- 通识课权限 -->
          <el-form-item label="通识课">
            <el-card class="w-full h-300px !overflow-y-scroll" shadow="never">
              <template #header>
                全选/全不选:
                <el-switch
                  v-model="generalTreeNodeAll"
                  active-text="是"
                  inactive-text="否"
                  inline-prompt
                  @change="handleCheckedGeneralTreeNodeAll()"
                />
                全部展开/折叠:
                <el-switch
                  v-model="generalDeptExpand"
                  active-text="展开"
                  inactive-text="折叠"
                  inline-prompt
                  @change="handleCheckedGeneralTreeExpand"
                />
                父子联动:
                <el-switch v-model="generalCheckStrictly" active-text="是" inactive-text="否" inline-prompt />
              </template>
              <el-tree
                ref="generalTreeRef"
                :check-strictly="!generalCheckStrictly"
                :data="generalCourseOptions"
                :props="defaultProps"
                default-expand-all
                empty-text="加载中，请稍后"
                node-key="id"
                show-checkbox
              />
            </el-card>
          </el-form-item>
        </el-col>
        <el-col :span="12">
          <!-- 实操课权限 -->
          <el-form-item label="实操课">
            <el-card class="w-full h-300px !overflow-y-scroll" shadow="never">
              <template #header>
                全选/全不选:
                <el-switch
                  v-model="practicalTreeNodeAll"
                  active-text="是"
                  inactive-text="否"
                  inline-prompt
                  @change="handleCheckedPracticalTreeNodeAll()"
                />
                全部展开/折叠:
                <el-switch
                  v-model="practicalDeptExpand"
                  active-text="展开"
                  inactive-text="折叠"
                  inline-prompt
                  @change="handleCheckedPracticalTreeExpand"
                />
                父子联动:
                <el-switch v-model="practicalCheckStrictly" active-text="是" inactive-text="否" inline-prompt />
              </template>
              <el-tree
                ref="practicalTreeRef"
                :check-strictly="!practicalCheckStrictly"
                :data="practicalCourseOptions"
                :props="defaultProps"
                default-expand-all
                empty-text="加载中，请稍后"
                node-key="id"
                show-checkbox
              />
            </el-card>
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>

    <template #footer>
      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
      <el-button @click="dialogVisible = false">取 消</el-button>
    </template>
  </Dialog>
</template>
<script lang="ts" setup>
import { defaultProps } from '@/utils/tree'
import * as RoleApi from '@/api/system/role'
import { CourseApi } from '@/api/bjdx/course'
import * as PermissionApi from '@/api/system/permission'

defineOptions({ name: 'SystemRoleCoursePermissionForm' })

const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗

const dialogVisible = ref(false) // 弹窗的是否展示
const formLoading = ref(false) // 表单的加载中：1）修改时的数据加载；2）提交的按钮禁用
const formData = reactive({
  id: undefined,
  name: '',
  code: '',
  dataScopeCourseIds: []
})
const formRef = ref() // 表单 Ref

// 通识课相关变量
const generalCourseOptions = ref<any[]>([]) // 通识课树形结构
const generalDeptExpand = ref(true) // 通识课展开/折叠
const generalTreeRef = ref() // 通识课菜单树组件 Ref
const generalTreeNodeAll = ref(false) // 通识课全选/全不选
const generalCheckStrictly = ref(true) // 通识课是否严格模式

// 实操课相关变量
const practicalCourseOptions = ref<any[]>([]) // 实操课树形结构
const practicalDeptExpand = ref(true) // 实操课展开/折叠
const practicalTreeRef = ref() // 实操课菜单树组件 Ref
const practicalTreeNodeAll = ref(false) // 实操课全选/全不选
const practicalCheckStrictly = ref(true) // 实操课是否严格模式

/** 打开弹窗 */
const open = async (row: RoleApi.RoleVO) => {
  dialogVisible.value = true
  resetForm()
  // 加载课程列表
  const allCourses = await CourseApi.getCourseTypeTree()
  
  // 修复筛选逻辑，确保通识课和实操课数据完全独立
  generalCourseOptions.value = filterCoursesByType(allCourses, '通识课')
  practicalCourseOptions.value = filterCoursesByType(allCourses, '实操课')
  
  // 设置数据
  formData.id = row.id
  formData.name = row.name
  formData.code = row.code
  await nextTick()
  
  // 需要在 DOM 渲染完成后，再设置选中状态
  if (row.dataScopeCourseIds && row.dataScopeCourseIds.length > 0) {
    row.dataScopeCourseIds.forEach((courseId: number): void => {
      // 尝试在两个树中都设置选中状态，实际只会在对应树中找到匹配的节点
      generalTreeRef.value?.setChecked(courseId * 100, true, false)
      practicalTreeRef.value?.setChecked(courseId * 100, true, false)
    })
  }
}

defineExpose({ open }) // 提供 open 方法，用于打开弹窗

/**
 * 根据课程类型筛选课程，并保留完整的树结构
 * @param courses 原始课程树数据
 * @param type 课程类型
 * @returns 筛选后的课程树数据
 */
function filterCoursesByType(courses: any[], type: string): any[] {
  // 深拷贝原始数据，避免修改原始数组
  const filteredCourses = JSON.parse(JSON.stringify(courses))
  
  // 递归处理树结构，只保留指定类型的节点及其父节点
  function filterTreeNodes(nodes: any[]): any[] {
    return nodes
      .map(node => {
        // 复制当前节点
        const newNode = { ...node }
        
        // 递归处理子节点
        if (node.children && node.children.length > 0) {
          const filteredChildren = filterTreeNodes(node.children)
          if (filteredChildren.length > 0) {
            newNode.children = filteredChildren
            return newNode
          }
        }
        
        // 如果当前节点是指定类型，或者有符合条件的子节点，则保留
        if (node.type === type) {
          return newNode
        }
        
        return null
      })
      .filter(node => node !== null)
  }
  
  return filterTreeNodes(filteredCourses)
}

/** 提交表单 *//** 提交表单 */
const emit = defineEmits(['success'])
const submitForm = async () => {
  formLoading.value = true
  try {
    // 获取所有选中的节点
    const generalCheckedKeys = generalTreeRef.value?.getCheckedKeys(false) || []
    const practicalCheckedKeys = practicalTreeRef.value?.getCheckedKeys(false) || []
    const allCheckedKeys = [...generalCheckedKeys, ...practicalCheckedKeys]
    
    // 过滤出只包含子节点的ID
    // 由于我们已经分别筛选了数据，这里直接合并两个数组
    const allCourseOptions = [...generalCourseOptions.value, ...practicalCourseOptions.value]
    const childNodeKeys = filterChildNodeKeys(allCheckedKeys, allCourseOptions)
    
    const data = {
      roleId: formData.id,
      dataScopeCourseIds: childNodeKeys
    }
    
    await PermissionApi.assignRoleCourseScope(data)
    message.success(t('common.updateSuccess'))
    dialogVisible.value = false
    // 发送操作成功的事件
    emit('success')
  } finally {
    formLoading.value = false
  }
}

/**
 * 过滤只包含子节点的ID
 * @param checkedKeys 所有选中的节点ID
 * @param treeData 树结构数据
 * @returns 只包含子节点的ID数组
 */
function filterChildNodeKeys(checkedKeys: number[], treeData: any[]): number[] {
  // 创建一个Map存储所有节点ID及其是否为叶子节点的状态
  const nodeMap = new Map<number, boolean>()

  // 递归遍历树结构，标记每个节点是否为叶子节点
  function traverseTree(nodes: any[]) {
    nodes.forEach(node => {
      nodeMap.set(node.id, node.type === "course")
      
      // 递归处理子节点
      if (node.children && node.children.length > 0) {
        traverseTree(node.children)
      }
    })
  }
  
  // 执行遍历
  traverseTree(treeData)
  
  // 过滤出只包含叶子节点的ID
  return checkedKeys.filter(key => {
    // 如果节点存在于nodeMap中且是叶子节点，则保留
    return nodeMap.has(key) && nodeMap.get(key)
  })
}

/** 重置表单 */
const resetForm = () => {
  // 重置通识课选项
  generalTreeNodeAll.value = false
  generalDeptExpand.value = true
  generalCheckStrictly.value = true
  generalTreeRef.value?.setCheckedNodes([])
  
  // 重置实操课选项
  practicalTreeNodeAll.value = false
  practicalDeptExpand.value = true
  practicalCheckStrictly.value = true
  practicalTreeRef.value?.setCheckedNodes([])
  
  // 重置表单
  formData.id = undefined
  formData.name = ''
  formData.code = ''
  formData.dataScopeCourseIds = []
  
  formRef.value?.resetFields()
}

/** 通识课全选/全不选 */
const handleCheckedGeneralTreeNodeAll = () => {
  generalTreeRef.value?.setCheckedNodes(generalTreeNodeAll.value ? generalCourseOptions.value : [])
}

/** 实操课全选/全不选 */
const handleCheckedPracticalTreeNodeAll = () => {
  practicalTreeRef.value?.setCheckedNodes(practicalTreeNodeAll.value ? practicalCourseOptions.value : [])
}

/** 通识课展开/折叠全部 */
const handleCheckedGeneralTreeExpand = () => {
  const nodes = generalTreeRef.value?.store.nodesMap
  if (nodes) {
    for (let node in nodes) {
      if (nodes[node].expanded === generalDeptExpand.value) {
        continue
      }
      nodes[node].expanded = generalDeptExpand.value
    }
  }
}

/** 实操课展开/折叠全部 */
const handleCheckedPracticalTreeExpand = () => {
  const nodes = practicalTreeRef.value?.store.nodesMap
  if (nodes) {
    for (let node in nodes) {
      if (nodes[node].expanded === practicalDeptExpand.value) {
        continue
      }
      nodes[node].expanded = practicalDeptExpand.value
    }
  }
}
</script>
