<template>
  <BasicModal
    wrapClassName="autherizeDialog"
    v-bind="$attrs"
    @register="registerRoleAuthModal"
    :title="t('功能授权')"
    destroy-on-close
    @ok="handleSubmit"
    :width=modalLength()
  >
      <template #title>
          <div>功能授权<span style="color:red">（注意：修改角色权限后需要手动点击“登出角色用户”按钮，或用户重新登录后才会生效）</span></div>
      </template>
    <a-row :gutter="[16, 16]" class="h-full">
      <a-col :span=spanLength() v-if="typeKey==4||typeKey==0">
        <div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
          t('系统功能')
        }}</div>
        <div class="treebox">
          <BasicTree
            :treeData="treeData"
            checkable
            ref="treeRef"
            @check="handleTreeSelect"
            :fieldNames="{ title: 'title', key: 'id' }"
          >
            <template #title="{ title, systemName, parentId }">
              <div v-if="parentId == 0">{{ title }} 【{{ systemName }}】</div>
              <div v-else>{{ title }}</div>
            </template>
          </BasicTree>
        </div>
      </a-col>
      <a-col :span=spanLength() v-if="typeKey==4||typeKey==1">
        <div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
          t('按钮权限')
        }}</div>
        <div class="treebox">
          <BasicTree
            :treeData="buttonSelectData"
            checkable
            ref="ButtonRef"
            @check="handleButtonSelect"
            :fieldNames="{ title: 'title', key: 'id' }"
          />
        </div>
      </a-col>
      <a-col :span=spanLength() v-if="typeKey==4||typeKey==2">
        <div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
          t('字段权限')
        }}</div>
        <div class="treebox">
          <BasicTree
            :treeData="columnSelectData"
            checkable
            ref="ColumnRef"
            @check="handleColumnSelect"
            :fieldNames="{ title: 'title', key: 'id' }"
          />
        </div>
      </a-col>
      <a-col :span=spanLength() v-if="typeKey==4||typeKey==3">
        <div class="text-base border-l-6 border-[#5e95ff] pl-3 h-5 leading-5 mb-3 ml-2">{{
          t('表单权限')
        }}</div>
        <div class="treebox">
          <BasicTree
            :treeData="fieldSelectData"
            checkable
            ref="FieldRef"
            @check="handleFieldSelect"
            :fieldNames="{ title: 'title', key: 'id' }"
          />
        </div>
      </a-col>
    </a-row>
  </BasicModal>
</template>
<script lang="ts">
  import { defineComponent, ref, unref, nextTick } from 'vue';
  import { getMenuSimpleTree } from '/@/api/system/menu';
  import { BasicModal, useModalInner } from '/@/components/Modal';
  import { TreeItem, BasicTree, TreeActionType } from '/@/components/Tree';
  import { getRoleAuth, RoleSetAuth } from '/@/api/system/role';
  import { useMessage } from '/@/hooks/web/useMessage';

  import { getMenuButtonList, getMenuColumnList, getMenuFieldList } from '/@/api/system/menuButton';
  import { cloneDeep } from 'lodash-es';
  import { useI18n } from '/@/hooks/web/useI18n';

  export default defineComponent({
    name: 'SelectUserModal',
    components: { BasicModal, BasicTree },
    emits: ['success', 'register'],
    setup(_, { emit }) {
      const { notification } = useMessage();
      const { t } = useI18n();
      const treeRef = ref<Nullable<TreeActionType>>(null);
      const ButtonRef = ref<Nullable<TreeActionType>>(null);
      const ColumnRef = ref<Nullable<TreeActionType>>(null);
      const FieldRef = ref<Nullable<TreeActionType>>(null);
      const treeData = ref<TreeItem[]>([]);
      const buttonData = ref<TreeItem[]>([]);
      const columnData = ref<TreeItem[]>([]);
      const fieldData = ref<TreeItem[]>([]);

      const buttonSelectData = ref<TreeItem[]>([]);
      const columnSelectData = ref<TreeItem[]>([]);
      const fieldSelectData = ref<TreeItem[]>([]);
      const btnKeys = ref<string[]>([]);
      const colKeys = ref<string[]>([]);
      const menuKeys = ref<string[]>([]);
      const fieldKeys = ref<string[]>([]);

      const btnFilterKeys = ref<string[]>([]);
      const colFilterKeys = ref<string[]>([]);
      const fieldFilterKeys = ref<string[]>([]);

      const rowId = ref('');
      const typeKey = ref(4);

      function getTree(tree) {
        if (!tree) {
          return null;
        }
        return tree;
      }

      function spanLength() {
        if (typeKey.value == 4) {
          return "6";
        } else {
          return "24";
        }
      }

      function modalLength() {
        if (typeKey.value == 4) {
          return "90%";
        } else {
          return "40%";
        }
      }

      const [registerRoleAuthModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
        setModalProps({ confirmLoading: false });
        rowId.value = data.id;
        typeKey.value = data.key;
        treeData.value = await getMenuSimpleTree();

        buttonData.value = await getMenuButtonList();
        columnData.value = await getMenuColumnList();
        fieldData.value = await getMenuFieldList();

        const authList = await getRoleAuth(rowId.value);
        menuKeys.value = authList.menuIds || [];
        btnKeys.value = authList.buttonIds || [];
        colKeys.value = authList.columnIds || [];
        fieldKeys.value = authList.formIds || [];
        let menuCheckedKey = [];
        let btnCheckedKey = [];
        let colCheckedKey = [];
        let fieldCheckedKey = [];
        if (typeKey.value == 4) {
          menuKeys.value.forEach((o) => {
            getParentKeys(menuCheckedKey, treeData.value, o);
          });
          menuKeys.value = menuCheckedKey;
          getTree(unref(treeRef)).setCheckedKeys(authList.menuIds);
          initTree(menuCheckedKey);

          let lostBtnKey = [];
          btnKeys.value.forEach((o) => {
            // getParentKeys(btnCheckedKey, buttonSelectData.value, o, lostBtnKey);
            getParentKeysAndLost(btnCheckedKey, buttonSelectData.value, o, lostBtnKey);
          });
          if (lostBtnKey) {
            let menuIds = [];
            buttonData.value.forEach((but) => {
              if (lostBtnKey.includes(but.id)) {
                menuIds.push(but.menuId);
              }
            });
            menuIds.forEach((key) => {
              getParentKeys(btnCheckedKey, treeData.value, key);
            });
            findMenuTree(buttonSelectData.value, treeData.value, btnCheckedKey, 'button');
          }
          btnKeys.value = Array.from(new Set([...btnKeys.value, ...btnCheckedKey]));
          
          let lostColKey = [];
          colKeys.value.forEach((o) => {
            // getParentKeys(colCheckedKey, columnSelectData.value, o);
            getParentKeysAndLost(colCheckedKey, columnSelectData.value, o, lostColKey);
          });
          if (lostColKey) {
            let menuIds = [];
            columnData.value.forEach((but) => {
              if (lostColKey.includes(but.id)) {
                menuIds.push(but.menuId);
              }
            });
            menuIds.forEach((key) => {
              getParentKeys(colCheckedKey, treeData.value, key);
            });
            findMenuTree(columnSelectData.value, treeData.value, colCheckedKey, 'column');
          }
          colKeys.value = Array.from(new Set([...colKeys.value, ...colCheckedKey]));

          let lostFieldKey = [];
          fieldKeys.value.forEach((o) => {
            // getParentKeys(fieldCheckedKey, fieldSelectData.value, o);
            getParentKeysAndLost(fieldCheckedKey, fieldSelectData.value, o, lostFieldKey);
          });
          if (lostFieldKey) {
            let menuIds = [];
            columnData.value.forEach((but) => {
              if (lostFieldKey.includes(but.id)) {
                menuIds.push(but.menuId);
              }
            });
            menuIds.forEach((key) => {
              getParentKeys(fieldCheckedKey, treeData.value, key);
            });
            findMenuTree(fieldSelectData.value, treeData.value, fieldCheckedKey, 'field');
          }
          fieldKeys.value = Array.from(new Set([...fieldKeys.value, ...fieldCheckedKey]));

          nextTick(() => {
            getTree(unref(ButtonRef))?.setCheckedKeys(authList.buttonIds);
            getTree(unref(ColumnRef))?.setCheckedKeys(authList.columnIds);
            getTree(unref(FieldRef))?.setCheckedKeys(authList.formIds);
            getTree(unref(ButtonRef)).expandAll(true);
            getTree(unref(ColumnRef)).expandAll(true);
            getTree(unref(FieldRef)).expandAll(true);
          });

          getTree(unref(treeRef)).expandAll(true);
        } else {
          if (typeKey.value == 0) {
            menuKeys.value.forEach((o) => {
              getParentKeys(menuCheckedKey, treeData.value, o);
            });
            menuKeys.value = menuCheckedKey;
            getTree(unref(treeRef)).setCheckedKeys(authList.menuIds);
            getTree(unref(treeRef)).expandAll(true);
          } 
          const fullMenuKey = [];
          getFullMenu(fullMenuKey, treeData.value);
          initTree(fullMenuKey);
          if (typeKey.value == 1) {
            btnKeys.value.forEach((o) => {
              getParentKeys(btnCheckedKey, buttonData.value, o);
            });
            btnKeys.value = btnCheckedKey;
            getTree(unref(ButtonRef))?.setCheckedKeys(authList.buttonIds);
            getTree(unref(ButtonRef)).expandAll(true);
          } 
          else if (typeKey.value == 2) {
            colKeys.value.forEach((o) => {
              getParentKeys(colCheckedKey, columnData.value, o);
            });
            colKeys.value = colCheckedKey;
            nextTick(() => {
              getTree(unref(ColumnRef))?.setCheckedKeys(authList.columnIds);
              getTree(unref(ColumnRef)).expandAll(true);
            });
          }
          else if (typeKey.value == 3) {
            fieldKeys.value.forEach((o) => {
              getParentKeys(fieldCheckedKey, fieldData.value, o);
            });
            fieldKeys.value = fieldCheckedKey;
            nextTick(() => {
              getTree(unref(FieldRef))?.setCheckedKeys(authList.formIds);
              getTree(unref(FieldRef)).expandAll(true);
            });
          }
          
        }
      });

      async function handleSubmit() {
        try {
          setModalProps({ confirmLoading: true });

          //由于树组件的原因，提交之前先过滤一遍，没有选中的不提交
          // btnKeys.value = getTree(unref(ButtonRef)).getCheckedKeys();
          // colKeys.value = getTree(unref(ColumnRef)).getCheckedKeys();
          // fieldKeys.value = getTree(unref(FieldRef)).getCheckedKeys();

          // 过滤无效的权限 ID
          btnKeys.value = btnKeys.value.filter((o) => btnFilterKeys.value.includes(o));
          colKeys.value = colKeys.value.filter((o) => colFilterKeys.value.includes(o));
          fieldKeys.value = fieldKeys.value.filter((o) => fieldFilterKeys.value.includes(o));

          // btnKeys.value = btnKeys.value.filter((o) => {
          //   return btnFilterKeys.value.includes(o);
          // });
          // colKeys.value = colKeys.value.filter((o) => {
          //   return colFilterKeys.value.includes(o);
          // });
          // fieldKeys.value = fieldKeys.value.filter((o) => {
          //   return fieldFilterKeys.value.includes(o);
          // });

          // 提交更新后的权限数据
          await RoleSetAuth({
            id: rowId.value,
            type: typeKey.value == 4?NaN:typeKey.value,
            menuIds: menuKeys.value,
            buttonIds: btnKeys.value,
            columnIds: colKeys.value,
            formIds: fieldKeys.value,
          });

          notification.success({
            message: t('提示'),
            description: t('功能授权更新成功'),
          }); //提示消息
          closeModal();
          emit('success');
        } catch (error) {
          setModalProps({ confirmLoading: false });
        }
      }
      function handleButtonSelect(keys, e) {
        btnKeys.value = [...e.halfCheckedKeys, ...keys];
      }
      function handleColumnSelect(keys, e) {
        colKeys.value = [...e.halfCheckedKeys, ...keys];
      }
      function handleFieldSelect(keys, e) {
        fieldKeys.value = [...e.halfCheckedKeys, ...keys];
      }
      function handleTreeSelect(keys, e) {
        //keys  所有全选中的key
        //e.halfCheckedKeys  所有半选中的

        //如果没有半选  就证明全部全选  直接使用keys
        //如果有半选需要  使用keys + e.halfCheckedKeys

        const menuSelect: string[] = [...e.halfCheckedKeys, ...keys];

        //选择菜单的时候。对应后面的button column field 只进行增量添加
        incrementTree(menuSelect);

        menuKeys.value = menuSelect;
      }
      function initTree(menuSelect) {
        buttonSelectData.value = [];
        columnSelectData.value = [];
        fieldSelectData.value = [];

        btnFilterKeys.value = [];
        colFilterKeys.value = [];
        fieldFilterKeys.value = [];

        findMenuTree(buttonSelectData.value, treeData.value, menuSelect, 'button');
        findMenuTree(columnSelectData.value, treeData.value, menuSelect, 'column');
        findMenuTree(fieldSelectData.value, treeData.value, menuSelect, 'field');

        getTree(unref(ButtonRef))?.setExpandedKeys(menuSelect);
        getTree(unref(ColumnRef))?.setExpandedKeys(menuSelect);
        getTree(unref(FieldRef))?.setExpandedKeys(menuSelect);
      }
      function incrementTree(addMenuSelect) {
        btnFilterKeys.value = [];
        colFilterKeys.value = [];
        fieldFilterKeys.value = [];

        // 使用 Set 合并已选中和新增选中的菜单，避免重复
        const allMenuKeys = new Set([...menuKeys.value, ...addMenuSelect]);

        // 确保未选中菜单的子节点不会丢失
        findMenuTree(buttonSelectData.value, treeData.value, Array.from(allMenuKeys), 'button');
        findMenuTree(columnSelectData.value, treeData.value, Array.from(allMenuKeys), 'column');
        findMenuTree(fieldSelectData.value, treeData.value, Array.from(allMenuKeys), 'field');

        // 更新按钮、字段、表单的选中状态
        btnKeys.value = Array.from(new Set([...btnKeys.value, ...addMenuSelect]));
        colKeys.value = Array.from(new Set([...colKeys.value, ...addMenuSelect]));
        fieldKeys.value = Array.from(new Set([...fieldKeys.value, ...addMenuSelect]));

        // 扩展树的展开状态
        getTree(unref(ButtonRef))?.setExpandedKeys(Array.from(allMenuKeys));
        getTree(unref(ColumnRef))?.setExpandedKeys(Array.from(allMenuKeys));
        getTree(unref(FieldRef))?.setExpandedKeys(Array.from(allMenuKeys));
      }
      function getParentKeys(checkedKey, arr, keys) {
        for (let i = 0; i < arr.length; i++) {
          let o = arr[i];
          if (o.id == keys) {
            checkedKey.push(o.id);
            if (o.parentId > 0 && !checkedKey.includes(o.parentId)) {
              checkedKey.push(o.parentId);
            }
          }
          if (o.children?.length > 0) {
            getParentKeys(checkedKey, o.children, keys);
          }
        }
      }
      // keys获取对应的菜单 返回给chackedKey，如果该keys 不在原先过滤后的数组arr中的话，把keys 记录lostKey抛出给外面二次处理，减少全数据过滤的内存处理
      function getParentKeysAndLost(checkedKey, arr, keys, lostKey) {
        for (let i = 0; i < arr.length; i++) {
          let o = arr[i];
          if (o.id == keys) {
            checkedKey.push(o.id);
            if (o.parentId > 0 && !checkedKey.includes(o.parentId)) {
              checkedKey.push(o.parentId);
            }
          }
          if (o.children?.length > 0) {
            getParentKeys(checkedKey, o.children, keys);
          }
        }
        if (!checkedKey.includes(keys)) {
          lostKey.push(keys);
        }
      }
      function findMenuTree(menuSelectTree, treeData, keys, type) {
        for (let i = 0; i < treeData.length; i++) {
          let o = cloneDeep(treeData[i]);
          if (keys.includes(o.id)) {
            let hadData = false;
            let index = 0;
            for (let j = 0; j < menuSelectTree.length; j++) {
              if (menuSelectTree[j].id == o.id) {
                hadData = true;
                index = j;
                break;
              }
            }
            if (!hadData) {
              o.children = [];
              menuSelectTree.push(o);
            } else {
              o = menuSelectTree[index];
            }
            if (treeData[i].children?.length > 0) {
              findMenuTree(o.children, treeData[i].children, keys, type);
            } else {
              let list =
                type == 'button'
                  ? buttonData.value
                  : type == 'column'
                  ? columnData.value
                  : fieldData.value;
              o.children = getAuthData(list, o.id, type);
            }
          }
        }
      }
      function getFullMenu(menuKeys, treeData) {
        for (let i = 0; i < treeData.length; i++) {
          let o = cloneDeep(treeData[i]);
          menuKeys.push(o.id);
          if (treeData[i].children?.length > 0) {
            getFullMenu(menuKeys, treeData[i].children)
          }
        }
      }
      function getAuthData(list, id, type) {
        let arr: TreeItem[] = [];

        arr = list.filter((o) => {
          return o.menuId == id;
        });

        arr.forEach((o) => {
          o.parentId = o.menuId;
          if (type == 'button') {
            btnFilterKeys.value.push(o.id);
          } else if (type == 'column') {
            colFilterKeys.value.push(o.id);
          } else {
            if (o.children && o.children.length > 0) {
              o.children?.forEach((k) => {
                fieldFilterKeys.value.push(k.id);
              });
            }
            fieldFilterKeys.value.push(o.id);
          }
        });
        return arr;
      }
      // function findMenuTree(menuTree, menuSelectTree, keys) {
      //   let selected: any = {};
      //   menuTree.forEach((key) => {
      //     //找到node对象

      //     if (keys.includes(key.id)) {
      //       console.log(key, 'kkkkkkkkkk');

      //       selected = cloneDeep(key);
      //       if (key.children?.length > 0) {
      //         selected.children = [];
      //         findMenuTree(key.children, selected.children, keys);
      //       }
      //     }
      //   });
      //   // let obj = menuSelectTree.find((o) => {
      //   //   return o.id == selected.id;
      //   // });
      //   // if (!obj) {
      //   //   menuSelectTree.push(selected);
      //   // } else {
      //   //   obj.children = obj.children.concat(selected.children);
      //   // }
      //   checkChild(menuSelectTree, selected);
      // }
      // function checkChild(menuTree, selected) {
      //   menuTree.forEach((o) => {
      //     if (o.id == selected.parentId) {
      //       o.children = o.children.concat(selected.children);
      //       checkChild(o.children, selected);
      //     } else {
      //       menuTree.push(selected);
      //     }
      //   });
      // }
      //将按钮塞入到菜单树
      // function menuInsertButton(menuTree, buttonList) {
      //   menuTree.forEach((menu) => {
      //     const thisMenuButton = buttonList.filter((btn) => btn.menuId === menu.id);
      //     if (menu.children && menu.children.length > 0) {
      //       menuInsertButton(menu.children, buttonList);
      //     }

      //     // console.log('thisMenuButton', thisMenuButton);

      //     menu.children = menu.children?.concat(thisMenuButton);
      //   });
      // }

      return {
        registerRoleAuthModal,
        handleSubmit,
        handleTreeSelect,
        handleButtonSelect,
        handleColumnSelect,
        handleFieldSelect,
        menuKeys,
        treeData,
        treeRef,
        ButtonRef,
        FieldRef,
        ColumnRef,
        buttonSelectData,
        columnSelectData,
        fieldSelectData,
        t,
        typeKey,
        spanLength,
        modalLength,
      };
    },
  });
</script>
<style lang="less">
  .autherizeDialog {
    .ant-modal {
      top: 20px;
      height: calc(100% - 40px) !important;

      .ant-modal-content {
        height: 100%;

        .ant-modal-body {
          height: calc(100% - 120px) !important;

          .scrollbar__view {
            height: 100%;

            & > div {
              height: 100%;
              max-height: none !important;

              .ant-col {
                height: 100%;

                .treebox {
                  height: calc(100% - 42px);
                  overflow: auto;
                  padding-right: 15px;
                  margin-bottom: 10px;
                  border-right: solid 1px #ccc;

                  .vben-tree {
                    height: auto;
                  }
                }
              }
            }
          }
        }
      }
    }
  }
</style>
