<script setup lang="ts">
import { computed, ComputedRef, reactive, ref, watch } from "vue";
import { useRole } from "./utils/hook";
import { PureTableBar } from "@/components/RePureTableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";

import Delete from "@iconify-icons/ep/delete";
import EditPen from "@iconify-icons/ep/edit-pen";
import Search from "@iconify-icons/ep/search";
import Refresh from "@iconify-icons/ep/refresh";
import AddFill from "@iconify-icons/ri/add-circle-line";
import { addRoleApi, AddRoleCommand, getRoleInfoApi, RoleDTO, updateRoleApi, UpdateRoleCommand } from "@/api/system/role";
import { ElMessage, FormRules } from "element-plus";
import { MenuDTO } from "@/api/system/menu";

defineOptions({
  name: "SystemRole"
});

const formRef = ref();
const menuTableRef = ref();
const {
  form,
  loading,
  columns,
  dataList,
  activeTab,
  pagination,
  onSearch,
  resetForm,
  menuTree,
  getMenuTree,
  handleDelete
} = useRole();

const opType = ref<"add" | "update">("add");
const opRow = ref<RoleDTO>();
const dataScope = ref<Record<number, string>>({});
const globalRole = {};
(window as any).globalRole = globalRole;
Object.assign(globalRole, { dataScope });

const formData = reactive<AddRoleCommand | UpdateRoleCommand>({
  roleId: 0,
  dataScope: "",
  menuIds: [],
  remark: "",
  roleKey: "",
  roleName: "",
  roleSort: 1,
  status: "1"
});
Object.assign(globalRole, { formData });
const resetFromData = () => {
  Object.assign(formData, {
    roleId: 0,
    dataScope: "",
    menuIds: [],
    remark: "",
    roleKey: "",
    roleName: "",
    roleSort: 1,
    status: "1"
  });
}
const rules: FormRules = {
  roleName: [
    {
      required: true,
      message: "角色名称不能为空"
    }
  ],
  roleKey: [
    {
      required: true,
      message: "权限标识不能为空"
    }
  ],
  roleSort: [
    {
      required: true,
      message: "角色序号不能为空"
    }
  ]
};

watch(activeTab, async (val) => {
  // console.log("activeTab", val); // 输出当前选中的标签的 key 或其他标识符
  opRow.value = dataList.value.find(item => item.roleKey == val);
  if (!opRow.value) {
    return;
  }
  await getRoleInfo("update", opRow.value);
  Object.assign(formData, opRow.value);
  formData.menuIds = opRow.value.selectedMenuList;
  updateDataScope(true);
});
async function getRoleInfo(type: "add" | "update", row?: RoleDTO) {
  try {
    await getMenuTree();
    if (row) {
      const { data } = await getRoleInfoApi(row.roleId);
      row.selectedMenuList = data.selectedMenuList;
      row.selectedDeptList = data.selectedDeptList;
    }
  } catch (e) {
    console.error(e);
    ElMessage.error((e as Error)?.message || "加载菜单失败");
  }
  opType.value = type;
  opRow.value = row;
}
interface MenuTableItem extends MenuDTO {
  _level: number;
  _rootId?: number;
  _rootName?: string;
  hasWritePermission?: boolean;
}

const menuTableData = ref<MenuTableItem[]>([]);
const permissionTableData = ref<PermissionTableRow[]>([]);
Object.assign(globalRole, { permissionTableData });
const maxLevel = ref(0);
const writePermissionMap = ref<Record<number, number>>({});

const convertMenuTreeToTableData = (menuTree: MenuDTO[]): MenuTableItem[] => {
  const writeMap: Record<number, number> = {};

  function filterTree(nodes: MenuDTO[], level: number, rootId?: number, rootName?: string): MenuTableItem[] {
    return nodes
      .filter(node => {
        const isWriteItem = node.menuName === '读写';
        if (isWriteItem && rootId) {
          writeMap[rootId] = node.id;
        }
        return !isWriteItem;
      })
      .map(node => {
        const currentRootId = rootId || node.id;
        const currentRootName = rootName || node.menuName;
        const hasWritePermission = level === 0 && !!writeMap[node.id];

        const newNode: MenuTableItem = {
          ...node,
          _level: level,
          _rootId: currentRootId,
          _rootName: currentRootName,
          hasWritePermission,
          children: node.children?.length
            ? filterTree(node.children, level + 1, currentRootId, currentRootName)
            : undefined
        };

        return newNode;
      });
  }

  const result = filterTree(menuTree, 0);
  writePermissionMap.value = writeMap;
  return result;
};

interface PermissionTableRow {
  _rootId: number;
  _rootName: string;
  _level: number;
  _hasWritePermission: boolean;
  _parentKey: string;
  _rowspanMap: Record<string, number>;
  level0: { id: number; name: string } | null;
  level1: { id: number; name: string } | null;
  level2: { id: number; name: string } | null;
  level3: { id: number; name: string } | null;
  level4: { id: number; name: string } | null;
}

const convertToFlatTableData = (menuTree: MenuDTO[], writeMap: Record<number, number>) => {
  const rows: PermissionTableRow[] = [];
  let maxLvl = 0;

  function traverse(
    node: MenuDTO,
    level: number,
    rootId: number,
    rootName: string,
    path: { id: number; name: string }[]
  ) {
    if (!node.id || !node.menuName) return;
    if (node.menuName === '读写') return;

    const currentPath = [...path, { id: node.id, name: node.menuName }];
    maxLvl = Math.max(maxLvl, level);

    const hasChildren = node.children && node.children.length > 0;
    const hasOnlyWriteChild = hasChildren && node.children.every(child => child.menuName === '读写');
    if (!hasChildren || hasOnlyWriteChild) {
      const row: PermissionTableRow = {
        _rootId: rootId,
        _rootName: rootName,
        _level: level,
        _hasWritePermission: !!writeMap[rootId],
        _parentKey: '',
        _rowspanMap: {},
        level0: currentPath[0] || null,
        level1: currentPath[1] || null,
        level2: currentPath[2] || null,
        level3: currentPath[3] || null,
        level4: currentPath[4] || null
      };
      rows.push(row);
    }

    if (node.children && node.children.length > 0) {
      node.children.forEach(child => {
        traverse(child, level + 1, rootId, rootName, currentPath);
      });
    }
  }

  menuTree.forEach(node => {
    if (!node.id || !node.menuName) return;
    if (node.menuName === '读写') return;
    traverse(node, 0, node.id, node.menuName, []);
  });

  if (rows.length > 0) {
    const rowspanMap: Record<string, number> = {};
    rows.forEach(row => {
      for (let i = 0; i < maxLvl + 1; i++) {
        const key = `level${i}`;
        const levelData = row[key as keyof PermissionTableRow];
        if (levelData && typeof levelData === 'object' && 'id' in levelData) {
          const id = (levelData as { id: number }).id;
          const mapKey = `${key}-${id}`;
          rowspanMap[mapKey] = (rowspanMap[mapKey] || 0) + 1;
        }
      }
    });
    rows.forEach(row => {
      row._rowspanMap = {};
      for (let i = 0; i < maxLvl + 1; i++) {
        const key = `level${i}`;
        const levelData = row[key as keyof PermissionTableRow];
        if (levelData && typeof levelData === 'object' && 'id' in levelData) {
          const id = (levelData as { id: number }).id;
          const mapKey = `${key}-${id}`;
          row._rowspanMap[key] = rowspanMap[mapKey];
        }
      }
    });
  }

  maxLevel.value = maxLvl + 1;
  return rows;
};

const getSpanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
  if (columnIndex === 0) {
    const prevRow = permissionTableData.value[rowIndex - 1];
    if (prevRow && prevRow._rootId === row._rootId) {
      return { rowspan: 0, colspan: 0 };
    }
    return { rowspan: row._rowspanMap["level0"] || 1, colspan: 1 };
  }
  const levelIndex = columnIndex - 1;
  const key = `level${levelIndex}`;
  const rowspan = row._rowspanMap?.[key] || 1;
  if (rowspan > 1) {
    const prevRow = permissionTableData.value[rowIndex - 1];
    const prevKey = `level${levelIndex}`;
    const prevLevelData = prevRow?.[prevKey as keyof PermissionTableRow];
    const currentLevelData = row[key as keyof PermissionTableRow];
    if (prevLevelData && currentLevelData &&
      typeof prevLevelData === 'object' && typeof currentLevelData === 'object' &&
      'id' in prevLevelData && 'id' in currentLevelData &&
      (prevLevelData as { id: number }).id === (currentLevelData as { id: number }).id) {
      return { rowspan: 0, colspan: 0 };
    }
  }
  return { rowspan, colspan: 1 };
};

watch(menuTree, (val) => {
  console.log('原始菜单树:', JSON.stringify(val, null, 2));

  // 分析树结构的函数
  function analyzeTree(nodes: MenuDTO[], level: number): {
    totalNodes: number,
    leafNodes: number,
    nodesByLevel: Record<number, number>
  } {
    let totalNodes = 0;
    let leafNodes = 0;
    const nodesByLevel: Record<number, number> = {};

    nodes.forEach(node => {
      totalNodes++;
      nodesByLevel[level] = (nodesByLevel[level] || 0) + 1;

      const hasChildren = node.children && node.children.length > 0;
      if (!hasChildren) {
        leafNodes++;
      }

      if (hasChildren) {
        const childStats = analyzeTree(node.children!, level + 1);
        totalNodes += childStats.totalNodes;
        leafNodes += childStats.leafNodes;
        Object.entries(childStats.nodesByLevel).forEach(([lvl, count]) => {
          nodesByLevel[Number(lvl)] = (nodesByLevel[Number(lvl)] || 0) + count;
        });
      }
    });

    return { totalNodes, leafNodes, nodesByLevel };
  }

  const stats = analyzeTree(val, 0);
  console.log('菜单树统计:', {
    总节点数: stats.totalNodes,
    叶子节点数: stats.leafNodes,
    非叶子节点数: stats.totalNodes - stats.leafNodes,
    各层级节点数: stats.nodesByLevel
  });

  menuTableData.value = convertMenuTreeToTableData(val);
  permissionTableData.value = convertToFlatTableData(val, writePermissionMap.value);

  console.log('转换后的表格数据:', permissionTableData.value);
  console.log('最大层级:', maxLevel.value);
});

// 统计某个顶层分类下是否有选中的菜单（递归遍历扁平表格）
const hasAnySelectedInCategory = (rootId: number): boolean => {
  return permissionTableData.value.some(row => {
    if (row._rootId !== rootId) return false;
    for (let i = 0; i < maxLevel.value; i++) {
      const key = `level${i}` as keyof PermissionTableRow;
      const levelData = row[key];
      if (levelData && typeof levelData === 'object' && 'id' in levelData && formData.menuIds.includes((levelData as { id: number }).id)) {
        return true;
      }
    }
    return false;
  });
};

// 监听菜单选择变化，更新数据权限
const updateDataScope = (updateAll: boolean) => {
  if (updateAll) dataScope.value = {};

  const topLevelMenuIds = [...new Set(permissionTableData.value.map(row => row._rootId))];

  topLevelMenuIds.forEach(rootId => {
    const hasSelected = hasAnySelectedInCategory(rootId);
    const writeItemId = writePermissionMap.value[rootId];

    if (hasSelected) {
      if (Number.isInteger(writeItemId) && formData.menuIds.includes(writeItemId)) {
        dataScope.value[rootId] = dataScope.value[rootId] || `${rootId}-1`;
      } else {
        dataScope.value[rootId] = dataScope.value[rootId] || `${rootId}-0`;
      }
    } else {
      dataScope.value[rootId] = null;
      if (writeItemId && formData.menuIds.includes(writeItemId)) {
        formData.menuIds = formData.menuIds.filter(id => id !== writeItemId);
      }
    }
  });
};

// 监听dataScope变化，反向更新menuIds
watch(
  dataScope,
  (newDataScope) => {
    Object.entries(newDataScope).forEach(([categoryId, scopeValue]) => {
      if (!scopeValue) {
        return;
      }
      const [id, permission] = scopeValue.split('-');
      const writeItemId = writePermissionMap.value[Number(id)];

      if (!writeItemId) return;

      if (permission === '1') {
        if (!formData.menuIds.includes(writeItemId)) {
          formData.menuIds.push(writeItemId);
        }
      } else {
        formData.menuIds = formData.menuIds.filter(menuId => menuId !== writeItemId);
      }
    });
  },
  { deep: true }
);

// 监听菜单选择变化，更新数据权限
watch(() => formData.menuIds,
  () => {
    updateDataScope(false);
  },
  { deep: true }
);

async function handleConfirm() {
  try {
    await formRef.value?.validate();
    loading.value = true;
    formData.dataScope = Object.values(dataScope.value).join(',');
    // console.log("opType", opType.value);
    if (opType.value === 'add') {
      await addRoleApi(formData as AddRoleCommand);
    } else {
      await updateRoleApi(formData as UpdateRoleCommand);
    }
    ElMessage.info("提交成功");
    onSearch().then(() => {
      activeTab.value = dataList.value[0].roleKey;
    });
  } catch (e) {
    console.error(e);
    ElMessage.error((e as Error)?.message || "提交失败");
  } finally {
    loading.value = false;
  }
}
const addRole = async () => {
  await getRoleInfo("add");
  activeTab.value = '';
  resetFromData();
}

getMenuTree();
onSearch().then(() => {
  activeTab.value = dataList.value[0].roleKey;
});
</script>
<template>
  <div class="main">

    <div class="tab-header">
      <el-button :icon="useRenderIcon(AddFill)" @click="addRole" style="margin-bottom: 16px">
        新建角色
      </el-button>
      <ul class="role-list">
        <li v-for="role in dataList" :key="role.roleKey" :class="{ 'active': activeTab === role.roleKey }"
          @click="activeTab = role.roleKey">
          {{ role.roleName }}
        </li>
      </ul>
    </div>
    <el-form :model="formData" label-width="120px" :rules="rules" ref="formRef">
      <el-form-item prop="roleName" label="角色名称" required inline-message>
        <el-input v-model="formData.roleName" class="form-input" />
      </el-form-item>
      <el-form-item prop="roleKey" label="权限字符" required>
        <el-input v-model="formData.roleKey" class="form-input" />
      </el-form-item>
      <!-- <el-form-item prop="roleSort" label="角色顺序" required>
        <el-input-number :min="1" v-model="formData.roleSort" />
      </el-form-item> -->
      <!-- <el-form-item prop="status" label="角色状态">
        <el-radio-group v-model="formData.status">
          <el-radio v-for="item in Object.keys(statusList)" :key="item" :label="statusList[item].value">{{
            statusList[item].label }}</el-radio>
        </el-radio-group>
      </el-form-item> -->
      <el-table ref="menuTableRef" :data="permissionTableData" row-key="id" border class="menu-permission-table"
        :span-method="getSpanMethod">
        <el-table-column label="数据权限" width="180" align="center">
          <template #default="{ row, $index }">
            <template
              v-if="row._hasWritePermission && ($index === 0 || permissionTableData[$index - 1]._rootId !== row._rootId)">
              <el-radio-group v-model="dataScope[row._rootId]" size="small">
                <el-radio :label="`${row._rootId}-0`" class="radio-item">只读</el-radio>
                <el-radio :label="`${row._rootId}-1`" class="radio-item">读写</el-radio>
              </el-radio-group>
            </template>
          </template>
        </el-table-column>
        <el-table-column v-for="level in maxLevel" :key="level - 1" :label="`${level}级菜单`" :width="220">
          <template #default="{ row }">
            <template v-if="row[`level${level - 1}`]">
              <el-checkbox-group v-model="formData.menuIds">
                <el-checkbox :label="row[`level${level - 1}`].id" class="menu-checkbox">
                  {{ row[`level${level - 1}`].name }}
                </el-checkbox>
              </el-checkbox-group>
            </template>
          </template>
        </el-table-column>
      </el-table>
      <!-- <el-form-item prop="remark" label="备注" style="margin-bottom: 0">
        <el-input type="textarea" class="form-input" v-model="formData.remark" />
      </el-form-item> -->
      <el-form-item class="form-actions">
        <el-button type="primary" @click="handleConfirm">确认</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>

<style scoped lang="scss">
.role-list {
  list-style: none;
  padding: 0;
  margin: 0;

  li {
    width: 200px;
    padding: 6px 12px;
    cursor: pointer;
    transition: all 0.3s;
    border-left: 3px solid transparent;
    font-weight: 700;
    font-size: 16px;

    &:hover {
      background-color: var(--el-color-primary-light-9);
    }

    &.active {
      background-color: var(--el-color-primary-light-8);
      /* border-left-color: var(--el-color-primary); */
      color: var(--el-color-primary);
    }
  }
}

:deep(.el-dropdown-menu__item i) {
  margin: 0;
}

.search-form {
  :deep(.el-form-item) {
    margin-bottom: 12px;
  }
}

.main {
  display: flex;
  gap: 5px;
}

.tab-header {
  height: 86vh;
  padding: 20px 12px 12px 12px;
  background-color: #FFFFFF;
  flex: 0 0 0px;
}

.el-form {
  height: 86vh;
  padding-top: 20px;
  background-color: #FFFFFF;
  flex: 1;
  overflow-y: auto;
  max-height: 80vh;
}

.form-actions {
  margin-top: 20px;
  text-align: right;
}

.menu-permission-table {
  margin-top: 16px;

  :deep(.el-table__cell) {
    .el-checkbox {
      margin: 0;
    }
  }

  .el-checkbox-group {
    display: flex;
    align-items: center;

    .menu-checkbox {
      margin: 0;
    }
  }

  .el-radio-group {
    display: flex;
    flex-direction: column;
    gap: 4px;

    .radio-item {
      margin: 0;
    }
  }
}
</style>
