<template>
  <!-- 添加或修改互斥组抽屉 -->
  <el-drawer v-model="visibleProxy" :title="title" size="50%" append-to-body :close-on-click-modal="false" @closed="resetForm">
    <div class="drawer-content-wrapper" v-loading="drawerLoading" element-loading-text="数据加载中...">
      <el-card v-if="!drawerLoading" shadow="hover" class="box-card">
        <el-form ref="mutexGroupFormRef" :model="form" :rules="rules" label-width="100px">
          <!-- 基本信息区域 -->
          <div class="form-section">
            <div class="section-header">
              <el-icon class="header-icon"><document /></el-icon>
              <span class="section-title">基本信息</span>
            </div>
            <el-divider />
            <el-row :gutter="24">
              <el-col :span="12">
                <el-form-item label="互斥组名称" prop="groupName">
                  <el-input v-model="form.groupName" placeholder="请输入互斥组名称" clearable />
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="互斥组编码" prop="groupCode">
                  <el-tooltip content="用于系统内部识别，建议使用英文大写+下划线" placement="top">
                    <el-input v-model="form.groupCode" placeholder="请输入互斥组编码" clearable>
                      <template #suffix>
                        <el-icon class="input-icon"><question-filled /></el-icon>
                      </template>
                    </el-input>
                  </el-tooltip>
                </el-form-item>
              </el-col>
            </el-row>

            <el-row :gutter="24">
              <el-col :span="12">
                <el-form-item label="显示顺序" prop="groupSort">
                  <el-input-number v-model="form.groupSort" controls-position="right" :min="0" style="width: 100%" :max="1000" />
                </el-form-item>
              </el-col>
              <el-col :span="12">
                <el-form-item label="状态">
                  <el-radio-group v-model="form.status">
                    <el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
                  </el-radio-group>
                </el-form-item>
              </el-col>
            </el-row>

            <el-row>
              <el-col :span="24">
                <el-form-item label="备注">
                  <el-input v-model="form.remark" type="textarea" placeholder="请输入备注内容" :rows="2" maxlength="500" show-word-limit></el-input>
                </el-form-item>
              </el-col>
            </el-row>
          </div>

          <!-- 菜单配置区域 -->
          <div class="form-section menu-section">
            <div class="section-header">
              <el-icon class="header-icon"><menu /></el-icon>
              <span class="section-title">互斥菜单配置</span>
              <el-tag type="primary" size="small" effect="plain" class="selected-count-tag">已选中: {{ selectedCount }}</el-tag>
              <el-tag type="warning" size="small" effect="plain" class="warning-tag">
                同组菜单将互相排斥
              </el-tag>
            </div>
            <el-divider />

            <!-- 菜单操作工具栏 -->
            <div class="menu-toolbar">
              <div class="menu-actions">
                <el-button size="small" :type="menuExpand ? 'success' : 'default'" @click="toggleExpand">
                  <el-icon><expand /></el-icon>
                  {{ menuExpand ? '折叠' : '展开' }}
                </el-button>
                <el-button size="small" :type="menuNodeAll ? 'warning' : 'default'" @click="toggleAllSelect">
                  {{ menuNodeAll ? '全不选' : '全选' }}
                </el-button>
                <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect" class="parent-linked">父子联动</el-checkbox>
              </div>
              <div class="menu-actions">
                <el-button size="small" type="danger" :disabled="selectedCount === 0" @click="clearAllSelection">
                  <el-icon><delete /></el-icon>
                  清空选择
                </el-button>
              </div>
            </div>

            <!-- 搜索过滤区域 -->
            <div class="search-container">
              <el-input v-model="filterText" placeholder="输入关键字过滤菜单" clearable class="search-input">
                <template #prefix>
                  <el-icon><search /></el-icon>
                </template>
              </el-input>
            </div>

            <!-- 互斥说明 -->
            <div class="mutex-explanation">
              <el-alert
                title="互斥规则说明"
                type="info"
                :closable="false"
                show-icon
              >
                <p>• 同一个互斥组内的菜单之间互相排斥，不能同时分配给同一个角色</p>
                <p>• 建议将有业务冲突或权限冲突的菜单放在同一个互斥组中</p>
                <p>• 例如：用户管理、角色管理、权限管理可以设为一组，确保权限职责分离</p>
              </el-alert>
            </div>

            <!-- 菜单树区域 -->
            <el-tree
              ref="menuRef"
              :data="menuOptions"
              show-checkbox
              node-key="id"
              :default-expand-all="menuExpand"
              :check-strictly="!form.menuCheckStrictly"
              empty-text="暂无菜单数据"
              :props="{ label: 'label', children: 'children' }"
              :filter-node-method="filterNode"
              @check="handleNodeCheck"
              class="menu-tree"
              highlight-current
              v-loading="treeLoading"
              element-loading-text="菜单加载中..."
            >
              <template #default="{ node, data }">
                <span class="custom-tree-node">
                  <!-- 节点图标和标签 -->
                  <span class="node-info">
                    <el-icon v-if="data.menuType === 'M'" class="directory-icon"><folder /></el-icon>
                    <el-icon v-else-if="data.menuType === 'C'" class="menu-icon"><menu /></el-icon>
                    <el-icon v-else-if="data.menuType === 'F'" class="button-icon"><operation /></el-icon>
                    <span :class="getNodeClass(data.menuType)">{{ node.label }}</span>
                  </span>

                  <!-- 节点标签 -->
                  <span class="node-tag">
                    <el-tag v-if="data.menuType === 'M'" type="success" size="small">目录</el-tag>
                    <el-tag v-else-if="data.menuType === 'C'" type="primary" size="small">菜单</el-tag>
                    <el-tag v-else-if="data.menuType === 'F'" type="warning" size="small">按钮</el-tag>
                  </span>
                </span>
              </template>
            </el-tree>
          </div>
        </el-form>
      </el-card>
    </div>
    <template #footer>
      <div class="dialog-footer">
        <el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </template>
  </el-drawer>
</template>

<script setup lang="ts">
import { addMutexGroup, getMutexGroup, updateMutexGroup, getGroupMenuTreeselect } from '@/api/system/menuMutexGroup';
import { treeselect } from '@/api/system/menu';
import { MutexGroupForm, MutexGroupVO } from '@/api/system/menuMutexGroup/types';
import { MenuTreeOption } from '@/api/system/menu/types';
import { ComponentInternalInstance, computed, PropType, ref, watch } from 'vue';
import { Delete, Document, Expand, Folder, Menu, Operation, QuestionFilled, Search } from '@element-plus/icons-vue';

const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  },
  editType: {
    type: String,
    default: 'add'
  },
  rowData: {
    type: Object as PropType<MutexGroupVO | null>,
    default: null
  }
});

const emit = defineEmits(['update:visible', 'save']);

const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { sys_normal_disable } = toRefs<any>(proxy?.useDict('sys_normal_disable'));

// 可见性的双向绑定
const visibleProxy = computed({
  get: () => props.visible,
  set: (val) => emit('update:visible', val)
});

// 根据编辑类型决定标题
const title = computed(() => {
  if (props.editType === 'add') return '添加互斥组';
  if (props.editType === 'menu') return '配置互斥菜单';
  return '修改互斥组';
});

// 加载状态
const drawerLoading = ref(false);
const treeLoading = ref(false);
const buttonLoading = ref(false);

// 表单ref
const mutexGroupFormRef = ref();
const menuRef = ref();

// 树形菜单数据
const menuOptions = ref<MenuTreeOption[]>([]);

// 展开/全选状态
const menuExpand = ref(false);
const menuNodeAll = ref(false);

// 选中的数量
const selectedCount = ref(0);

// 搜索过滤
const filterText = ref('');

// 已选中的菜单列表
const selectedMenus = ref<any[]>([]);

// 初始化表单数据
const initFormData: MutexGroupForm = {
  groupId: undefined,
  groupName: '',
  groupCode: '',
  groupSort: 1,
  status: '0',
  remark: '',
  menuIds: [],
  menuCheckStrictly: true
};

// 表单数据
const form = ref<MutexGroupForm>({ ...initFormData });

// 表单校验规则
const rules = ref({
  groupName: [{ required: true, message: '互斥组名称不能为空', trigger: 'blur' }],
  groupCode: [{ required: true, message: '互斥组编码不能为空', trigger: 'blur' }],
  groupSort: [{ required: true, message: '显示顺序不能为空', trigger: 'blur' }]
});

/**
 * 过滤节点方法
 */
const filterNode = (value: string, data: any) => {
  if (!value) return true;
  return data.label.toLowerCase().includes(value.toLowerCase());
};

/**
 * 获取节点样式类
 */
const getNodeClass = (menuType: string): string => {
  switch (menuType) {
    case 'M':
      return 'directory-label';
    case 'C':
      return 'menu-label';
    case 'F':
      return 'button-label';
    default:
      return '';
  }
};

/**
 * 更新已选菜单列表
 */
const updateSelectedMenus = () => {
  if (!menuRef.value) {
    selectedMenus.value = [];
    selectedCount.value = 0;
    return;
  }

  try {
    const checkedNodes = menuRef.value.getCheckedNodes() || [];
    selectedMenus.value = checkedNodes;
    selectedCount.value = checkedNodes.length;
  } catch (error) {
    selectedMenus.value = [];
    selectedCount.value = 0;
  }
};

/**
 * 处理节点选中状态变更
 */
const handleNodeCheck = () => {
  if (menuRef.value) {
    updateSelectedMenus();
  }
};

/**
 * 清空所有选择
 */
const clearAllSelection = () => {
  if (menuRef.value) {
    menuRef.value.setCheckedKeys([]);
    updateSelectedMenus();
  }
};

/**
 * 切换展开状态
 */
const toggleExpand = () => {
  menuExpand.value = !menuExpand.value;
  handleCheckedTreeExpand(menuExpand.value);
};

/**
 * 切换全选状态
 */
const toggleAllSelect = () => {
  menuNodeAll.value = !menuNodeAll.value;
  handleCheckedTreeNodeAll(menuNodeAll.value);
};

/** 取消按钮 */
const cancel = (): void => {
  visibleProxy.value = false;
};

/** 表单重置 */
const resetForm = (): void => {
  form.value = { ...initFormData };
  selectedCount.value = 0;
  menuExpand.value = false;
  menuNodeAll.value = false;
  filterText.value = '';
  selectedMenus.value = [];
  menuOptions.value = [];
  mutexGroupFormRef.value?.resetFields();
  if (menuRef.value) {
    menuRef.value.setCheckedKeys([]);
  }
};

/**
 * 递归展开或折叠树节点
 */
const expandAllNodes = (expand: boolean, nodes: any[]) => {
  if (!nodes || !nodes.length) return;

  nodes.forEach((node) => {
    if (menuRef.value?.store.nodesMap[node.id]) {
      menuRef.value.store.nodesMap[node.id].expanded = expand;
    }

    if (node.children && node.children.length) {
      expandAllNodes(expand, node.children);
    }
  });
};

/** 树权限（展开/折叠）*/
const handleCheckedTreeExpand = (value: boolean): void => {
  menuExpand.value = value;
  expandAllNodes(value, menuOptions.value);
};

/** 树权限（全选/全不选） */
const handleCheckedTreeNodeAll = (value: boolean): void => {
  if (menuRef.value) {
    menuRef.value.setCheckedNodes(value ? menuOptions.value : []);
    updateSelectedMenus();
  }
};

/** 树权限（父子联动） */
const handleCheckedTreeConnect = (value: boolean): void => {
  form.value.menuCheckStrictly = value;
};

/** 所有菜单节点数据 */
const getMenuAllCheckedKeys = (): (string | number)[] => {
  if (!menuRef.value) return [];

  let checkedKeys = menuRef.value.getCheckedKeys() || [];
  const halfCheckedKeys = menuRef.value.getHalfCheckedKeys() || [];
  if (halfCheckedKeys && halfCheckedKeys.length) {
    checkedKeys = [...checkedKeys, ...halfCheckedKeys];
  }
  return checkedKeys;
};

/**
 * 获取菜单树数据
 */
const getMenuTreeselect = async (): Promise<void> => {
  treeLoading.value = true;
  try {
    const res = await treeselect();
    menuOptions.value = res.data;
  } catch (error) {
  } finally {
    treeLoading.value = false;
  }
};

/** 根据互斥组ID查询菜单树结构 */
const getGroupMenuTreeselectData = async (groupId: string | number) => {
  return getGroupMenuTreeselect(groupId).then((res) => {
    return res.data;
  });
};

/**
 * 提交表单
 */
const submitForm = (): void => {
  mutexGroupFormRef.value?.validate(async (valid: boolean) => {
    if (valid) {
      buttonLoading.value = true;
      try {
        form.value.menuIds = getMenuAllCheckedKeys();
        if (form.value.groupId) {
          await updateMutexGroup(form.value);
        } else {
          await addMutexGroup(form.value);
        }
        proxy?.$modal.msgSuccess('操作成功');
        emit('save');
        visibleProxy.value = false;
      } catch (error) {
      } finally {
        buttonLoading.value = false;
      }
    }
  });
};

// 监听器
watch([() => props.visible, () => props.editType, () => props.rowData], async ([visible, type, data]) => {
  if (visible) {
    drawerLoading.value = true;
    resetForm();
    try {
      // 加载菜单树
      await getMenuTreeselect();

      if ((type === 'edit' || type === 'menu') && data) {
        // 修改操作或菜单配置
        try {
          const res = await getMutexGroup(data.groupId);
          Object.assign(form.value, res.data);
          form.value.groupSort = Number(form.value.groupSort);

          // 获取互斥组菜单数据
          const menuIds = await getGroupMenuTreeselectData(data.groupId);
          setTimeout(() => {
            if (menuRef.value && menuIds.length > 0) {
              menuRef.value.setCheckedKeys(menuIds);
              updateSelectedMenus();
            }
          }, 200);
        } catch (error) {
        }
      }
    } finally {
      drawerLoading.value = false;
    }
  }
});

// 监听过滤文本变化
watch(filterText, (val) => {
  menuRef.value?.filter(val);
});
</script>

<style scoped>
/* 复用角色表单的样式，并添加一些互斥组特有的样式 */
.drawer-content-wrapper {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.box-card {
  height: calc(100vh - 120px);
  display: flex;
  flex-direction: column;
  padding: 0;
  background-color: #fcfcfc;
}

:deep(.el-form) {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 15px 20px;
}

:deep(.el-drawer__body) {
  padding: 0;
  overflow: hidden;
  height: calc(100% - 60px);
}

.form-section {
  margin-bottom: 20px;
  border-radius: 8px;
  background-color: #fff;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
  padding: 15px;
}

.section-header {
  display: flex;
  align-items: center;
  padding: 5px 0;
}

.header-icon {
  margin-right: 8px;
  font-size: 18px;
  color: #409eff;
}

.section-title {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
  margin-right: 10px;
}

.selected-count-tag {
  margin-left: 5px;
  font-weight: bold;
}

.warning-tag {
  margin-left: 10px;
  font-weight: 500;
}

.menu-section {
  flex: 1;
  display: flex;
  flex-direction: column;
  margin-bottom: 0;
  overflow: hidden;
}

.menu-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
  padding: 6px;
  background-color: #f6f8fa;
  border-radius: 6px;
  border: 1px solid #eaeefb;
}

.menu-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.search-container {
  margin-bottom: 10px;
}

.search-input :deep(.el-input__inner) {
  border-color: #dcdfe6;
}

.search-input :deep(.el-input__inner:focus) {
  border-color: #409eff;
}

.mutex-explanation {
  margin-bottom: 15px;
}

.mutex-explanation :deep(.el-alert__content) {
  padding-top: 0;
}

.mutex-explanation p {
  margin: 5px 0;
  font-size: 13px;
  line-height: 1.5;
}

.menu-tree {
  height: calc(100vh - 450px);
  min-height: 250px;
  border: 1px solid #e6e6e6;
  border-radius: 6px;
  padding: 6px;
  overflow: auto;
  background-color: #fff;
}

.menu-tree :deep(.el-tree-node__content) {
  height: 30px;
  margin: 0;
  border-radius: 4px;
}

.menu-tree :deep(.el-tree-node__content:hover) {
  background-color: #f0f7ff;
}

.menu-tree :deep(.el-tree-node.is-current > .el-tree-node__content) {
  background-color: #ecf5ff;
}

.menu-tree :deep(.el-checkbox__input.is-checked .el-checkbox__inner) {
  background-color: #409eff;
  border-color: #409eff;
}

.menu-tree :deep(.el-tree-node__expand-icon) {
  color: #67c23a;
  padding: 4px;
  margin-right: 2px;
}

.menu-tree :deep(.el-tree-node__children) {
  padding-left: 16px;
}

.custom-tree-node {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 28px;
  line-height: 28px;
}

.node-info {
  display: flex;
  align-items: center;
}

.node-tag {
  margin-left: auto;
}

.node-tag :deep(.el-tag) {
  padding: 0 4px;
  height: 20px;
  line-height: 20px;
}

.directory-icon {
  color: #e6a23c;
  margin-right: 4px;
  font-size: 16px;
}

.menu-icon {
  color: #409eff;
  margin-right: 4px;
  font-size: 16px;
}

.button-icon {
  color: #f56c6c;
  margin-right: 4px;
  font-size: 16px;
}

.directory-label {
  font-weight: bold;
  color: #303133;
}

.menu-label {
  font-weight: normal;
  color: #2c3e50;
}

.button-label {
  font-weight: normal;
  color: #606266;
}

.dialog-footer {
  display: flex;
  justify-content: center;
  gap: 10px;
}

:deep(.el-card__body) {
  padding: 10px;
  height: 100%;
  overflow: auto;
}

:deep(.el-divider--horizontal) {
  margin: 12px 0;
}

.parent-linked {
  color: #409eff;
  font-weight: 500;
}

:deep(.el-checkbox__input.is-checked + .el-checkbox__label) {
  color: #409eff;
}
</style>
