<template>
  <el-dialog v-model="visible" v-loading="loading" :title="title" :width="720" @close="colseDialogBackcall">
    <div class="role">
      <el-form-item label="角色名称" label-width="80px">
        <el-input v-model="roleName" class="input" placeholder="请输入输入角色名称" :readonly="actionType == 'read'" />
      </el-form-item>
    </div>

    <el-scrollbar class="h-300px py-10px">
      <!-- :show-checkbox="actionType !== 'read'" -->
      <el-tree :data="menuTree" node-key="id" :expand-on-click-node="actionType !== 'read'" :default-expand-all="true" style="--el-tree-node-content-height: 40px">
        <template #default="{ node, data }">
          <div v-if="editNode.id === data.id && data.id && canRename" class="flex-grow w-0 flex items-center group py-5px">
            <el-input v-model="editNode.label" ref="inputRef" class="w-100px" :placeholder="editNode.menuName || '请输入菜单名称'" />
            <el-icon v-if="nodeLoading" class="ml-10px animate-spin text-gray-500">
              <Refresh />
            </el-icon>
            <template v-else>
              <el-icon class="ml-10px cursor-pointer text-gray-500" @click="edit()">
                <CloseBold />
              </el-icon>
              <el-icon class="ml-10px cursor-pointer text-green-500" @click="confirm()">
                <Select />
              </el-icon>
            </template>
          </div>
          <div v-else class="flex-grow flex items-center group py-5px">
            <div v-if="actionType !== 'read'" class="mr-5px transform -translate-y-1px" @click.stop="toggle(data)">
              <el-checkbox :model-value="selectionMap[data.id] ? selectionMap[data.id].selected : false" />
            </div>
            <div class="flex align-center">
              <div class="w-100px">{{ data.customMenuName || data.label }}</div>
              <el-checkbox v-if="managerList.some((i) => data.id === i)" :model-value="selectManagerList.some((i) => i === data.id)" label="主管" class="ml-20px" @change="selectManager($event, data.id)" />
            </div>
            <div v-if="!nodeLoading && canRename" class="flex-shrink-0 hidden translate-y-2px transform ml-10px text-blue-500 cursor-pointer group-hover:block" @click="edit(data)">
              <el-icon size="16">
                <EditPen />
              </el-icon>
            </div>
          </div>
        </template>
      </el-tree>
    </el-scrollbar>
    <template #footer v-if="actionType != 'read'">
      <div class="dialog-footer" text-center>
        <el-button v-if="actionType == 'updateRole'" class="w-100px cancel-btn" @click="remove()">删除</el-button>
        <el-button v-else-if="actionType == 'addRole'" class="w-100px cancel-btn" @click="cancel">取消</el-button>
        <el-button class="w-100px" type="primary" @click="save">保存</el-button>
      </div>
    </template>
  </el-dialog>
</template>
<script setup>
import { computed, nextTick, ref } from "vue";
import { storeToRefs } from "pinia";
import { ElMessage } from "element-plus";
import { updateRole, createRole } from "@/api/corp";
import { getMenus as getMenusUrl, setCorpMenuConfig } from "@/api/system";
import { memberStore } from "@/store/member";
import { tagsStore } from "@/store/tags";

defineProps({ canRename: { type: Boolean, default: false } });
const emit = defineEmits(["on-add-role", "remove"]);
const titleConfig = { default: "新增角色", edit: "编辑角色", read: "查看详情" };
const actionConfig = { default: "addRole", edit: "updateRole", read: "read" };
const { memberInfo } = storeToRefs(memberStore());
const { setCustomMenuName } = tagsStore();

// 主管页面
const managerList = [10008, 10005, 10007,10009];
const selectManagerList = ref([]);
let roleName = ref("");
let role = {};
let title = ref("新增角色");
let actionType = "addRole"; // add 新增 edit 编辑

const currentRole = ref({});
const editNode = ref({});
const loading = ref(false);
const selectionMap = ref({});

const inputRef = ref(null);
const menus = ref([]);
const menuTree = computed(() => buildTree(menus.value, 0));
const nodeLoading = ref(false);
const visible = ref(false);

async function openDialog(type, item) {
  visible.value = true;
  let arr = await getMenus();
  if (item.managerList) {
    selectManagerList.value = item.managerList;
  } else {
    selectManagerList.value = [];
  }
  // arr 根据 sort 排序
  arr = arr.sort((a, b) => a.sort - b.sort);
  title.value = titleConfig[type] || titleConfig.default;
  actionType = actionConfig[type] || actionConfig.default;
  currentRole.value = { ...item };
  role = JSON.parse(JSON.stringify(item));
  const selectedMenuIds = Array.isArray(role.menuList) ? [...role.menuList] : [];
  selectedMenuIds.forEach((menuId) => {
    selectionMap.value[menuId] = { selected: true, menuId };
  });
  roleName.value = role.roleName || "";
  menus.value = type === "read" ? findByIdWithChildren(arr, selectedMenuIds) : arr;
}

async function getMenus() {
  loading.value = true;
  let { data, success } = await getMenusUrl();
  loading.value = false;
  if (success) {
    return data.data;
  } else {
    return [];
  }
}

function selectManager(item, num) {
  if (item) {
    selectManagerList.value.push(num);
  } else {
    selectManagerList.value = selectManagerList.value.filter((i) => i !== num);
  }
}

function remove() {
  visible.value = false;
  emit("remove", role);
}
function cancel() {
  visible.value = false;
}
async function save() {
  const selectedMenuIds = Object.keys(selectionMap.value)
    .filter((key) => selectionMap.value[key].selected)
    .map((key) => selectionMap.value[key].menuId);
  // 新增角色
  if (!roleName.value) {
    ElMessage({
      message: "请输入角色名称",
      type: "warning",
    });
    return;
  }
  if (!selectedMenuIds.length === 0) {
    ElMessage({
      message: "请选择角色权限",
      type: "warning",
    });
    return;
  }
  let params = {
    corpId: sessionStorage.getItem("corpId"),
    roleName: roleName.value,
    menuList: selectedMenuIds,
    managerList: selectManagerList.value,
  };
  let { success, message } = actionType === "updateRole" ? await updateRole(role._id, params) : await createRole(params);
  if (success) {
    visible.value = false;
    emit("on-add-role");
  } else {
    ElMessage({
      message,
      type: "warning",
    });
  }
}

function buildTree(rawData, parentId) {
  const result = [];
  rawData.forEach((item) => {
    if (item.parentId === parentId) {
      const children = buildTree(rawData, item.menuId);
      result.push({
        id: item.menuId,
        label: item.menuName,
        customMenuName: item.customMenuName,
        children: children.length ? children : [],
      });
    }
  });
  return result;
}

function colseDialogBackcall() {
  editNode.value = {};
  selectionMap.value = {};
  roleName.value = "";
}

function findByIdWithChildren(data, ids) {
  const menus = data.filter((i) => ids.includes(i.menuId));
  const menuIds = menus.reduce((arr, menu) => {
    if (menu.parentId) arr.push(menu.parentId);
    arr.push(menu.menuId);
    return arr;
  }, []);
  const uniqueMenuIds = [...new Set(menuIds)];
  return data.filter((i) => uniqueMenuIds.includes(i.menuId));
}

async function edit(data = {}) {
  if (nodeLoading.value) return;
  editNode.value = { id: data.id, label: data.customMenuName || "", menuName: data.label };
  if (data.id) {
    await nextTick();
    inputRef.value.focus();
  }
}

async function confirm() {
  if (!editNode.value.id || nodeLoading.value) return;
  if (typeof editNode.value.label == "string" && editNode.value.label.trim().length > 8) {
    return ElMessage.info("菜单名称最多输入八个字");
  }
  nodeLoading.value = true;
  const menuName = typeof editNode.value.label == "string" ? editNode.value.label.trim() : "";
  const { success, message } = await setCorpMenuConfig({
    corpId: memberInfo.value.corpId,
    menuId: editNode.value.id,
    menuName,
  });
  nodeLoading.value = false;
  if (success) {
    const index = menus.value.findIndex((i) => i.menuId == editNode.value.id);
    if (index > -1) {
      menus.value[index].customMenuName = editNode.value.label.trim();
    }
    setCustomMenuName(editNode.value.id, menuName);
    ElMessage.success("修改成功");
    edit();
  } else {
    ElMessage.error(message);
  }
}

function toggle(data) {
  const selected = selectionMap.value[data.id] ? selectionMap.value[data.id].selected : false;
  if (selected) {
    selectionMap.value[data.id].selected = false;
  } else {
    selectionMap.value[data.id] = { selected: true, menuId: data.id };
  }
  if (data.children && data.children.length) {
    data.children.forEach((child) => {
      selectionMap.value[child.id] = selectionMap.value[child.id] || { selected: false, menuId: child.id };
      selectionMap.value[child.id].selected = !selected;
    });
  }
}

defineExpose({
  openDialog,
});
</script>
<style scoped lang="scss">
.role {
  border-bottom: 1px solid #eee;
}

.input {
  width: 200px;
}

.left {
  width: 200px;
  padding: 15px;
  border-right: 1px solid #eee;
  max-height: 300px;
  overflow-y: auto;

  .title {
    border-bottom: 1px solid #eee;
    padding-bottom: 10px;
    display: flex;
  }
}

.auth_box {
  display: flex;
}
</style>
