<template>
  <doc-alert title="功能权限" url="https://doc.iocoder.cn/resource-permission" />
  <doc-alert title="菜单路由" url="https://doc.iocoder.cn/vue3/route/" />

  <div class="menu-management-container" :gutter="12" :class="{ 'no-gap': isTreeCollapsed }">
    <!-- 左侧菜单树 -->
    <div
      class="menu-tree-col"
      :class="{ 'tree-collapsed': isTreeCollapsed }"
      :style="{ height: tableHeight + 'px' }"
    >
      <MenuTree @node-click="handleMenuNodeClick" />
    </div>
    <div class="table-col">
      <div class="table-wrap">
        <!-- 表格部分使用TableList组件 -->
        <TableList ref="tableListRef" :config="tableListConfig" />
        <!-- 悬浮切换按钮 -->
        <div
          class="tree-toggle-btn"
          :class="{ collapsed: isTreeCollapsed }"
          @click="toggleTreeCollapse"
          :style="{
            top: tableHeight / 2 + 'px',
            left: buttonLeftPosition + 'px'
          }"
        >
          <Icon :icon="isTreeCollapsed ? 'ep:arrow-right' : 'ep:arrow-left'" />
        </div>
      </div>
    </div>
  </div>

  <!-- 表单弹窗：添加/修改 -->
  <MenuForm ref="formRef" @success="handleRefresh" />
</template>
<script lang="tsx" setup>
import { computed, h as createElement, ref, nextTick } from 'vue'
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { handleTree } from '@/utils/tree'
import { useAppStore } from '@/store/modules/app'
import { checkPermi } from '@/utils/permission'
import * as MenuApi from '@/api/system/menu'
import { MenuVO } from '@/api/system/menu'
import type { TableListConfig } from '@/components/TableList/types'
import TableList from '@/components/TableList/index.vue'
import MenuForm from './MenuForm.vue'
import MenuTree from './MenuTree.vue'
import DictTag from '@/components/DictTag/src/DictTag.vue'
import { Icon } from '@/components/Icon'
import { ElSwitch } from 'element-plus'
import { CommonStatusEnum } from '@/utils/constants'
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'

defineOptions({ name: 'SystemMenu' })

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

const appStore = useAppStore()
const isCollapsed = computed(() => appStore.getCollapse)

// 菜单状态更新中的映射
const menuStatusUpdating = ref({})
const allMenuList = ref<any[]>([]) // 存储完整的菜单树形数据
const queryParams = reactive({
  pageNo: 1,
  pageSize: 10,
  name: undefined,
  status: undefined,
  parentId: undefined
})
const tableListRef = ref<InstanceType<typeof TableList>>() // TableList组件引用

// 高度相关状态
const tableHeight = ref(600) // 表格高度
const isTreeCollapsed = ref(false) // 左侧树是否收起
const buttonLeftPosition = ref(0) // 按钮左位置

// 过滤菜单数据的函数
const filterMenuData = (data: any[], parentId?: number): any[] => {
  if (parentId === undefined) {
    // 没有选择父级时，不显示任何数据
    return []
  }

  // 找到选中的菜单，只返回该菜单本身（不包含children）
  const findMenuOnly = (menus: any[], targetId: number): any[] => {
    for (const menu of menus) {
      if (menu.id === targetId) {
        // 找到目标菜单，只返回该菜单本身，移除children
        const menuCopy = { ...menu }
        delete menuCopy.children
        return [menuCopy]
      }
      if (menu.children && menu.children.length > 0) {
        const found = findMenuOnly(menu.children, targetId)
        if (found && found.length > 0) {
          return found
        }
      }
    }
    return []
  }

  return findMenuOnly(data, parentId)
}

// 根据搜索条件过滤数据
const applySearchFilters = (data: any[], filters: any): any[] => {
  return data.filter((item) => {
    // 菜单名称过滤
    if (filters.name && !item.name.includes(filters.name)) {
      return false
    }
    // 状态过滤
    if (filters.status !== undefined && item.status !== filters.status) {
      return false
    }
    return true
  })
}

// TableList配置
const tableListConfig = computed(
  (): TableListConfig => ({
    searchForm: {
      items: [
        {
          field: 'name',
          label: '菜单名称',
          type: 'input',
          placeholder: '请输入菜单名称'
        },
        {
          field: 'status',
          label: '状态',
          type: 'select',
          placeholder: '请选择菜单状态',
          options: getIntDictOptions(DICT_TYPE.COMMON_STATUS)
        }
      ]
    },
    table: {
      columns: [
        {
          prop: 'name',
          label: '菜单名称',
          minWidth: 220
        },
        {
          prop: 'icon',
          label: '图标',
          width: 100,
          align: 'center',
          render: (passedH: any, { row }: { row: any }) => {
            const h = passedH || createElement
            return h(Icon, { icon: row.icon })
          }
        },
        {
          prop: 'sort',
          label: '排序',
          width: 60,
          align: 'center'
        },
        {
          prop: 'permission',
          label: '权限标识',
          width: 200
        },
        {
          prop: 'component',
          label: '组件路径',
          width: 200
        },
        {
          prop: 'componentName',
          label: '组件名称',
          width: 150
        },
        {
          prop: 'status',
          label: '状态',
          width: 80,
          fixed: 'right',
          align: 'center',
          render: (passedH: any, { row }: { row: any }) => {
            const h = passedH || createElement
            // 检查权限
            if (!checkPermi(['system:menu:update'])) {
              return h(DictTag, { type: DICT_TYPE.COMMON_STATUS, value: row.status })
            }

            // 如果有权限，渲染 ElSwitch
            return h(ElSwitch, {
              modelValue: row.status,
              activeValue: CommonStatusEnum.ENABLE,
              inactiveValue: CommonStatusEnum.DISABLE,
              loading: menuStatusUpdating.value[row.id],
              class: 'ml-4px',
              'onUpdate:modelValue': (val: number) => handleStatusChanged(row, val)
            })
          }
        }
      ],
      actions: [
        {
          label: '修改',
          type: 'primary',
          link: true,
          show: (row: any) => checkPermi(['system:menu:update']),
          handler: (row: any) => openForm('update', row.id)
        },
        {
          label: '新增',
          type: 'primary',
          link: true,
          show: (row: any) => checkPermi(['system:menu:create']),
          handler: (row: any) => openForm('create', undefined, row.id)
        },
        {
          label: '删除',
          type: 'danger',
          link: true,
          show: (row: any) => checkPermi(['system:menu:delete']),
          handler: (row: any) => handleDelete(row.id)
        }
      ],
      actionsWidth: 160
    },
    actions: [
      {
        label: '新增',
        type: 'primary',
        plain: false,
        icon: 'ep:plus',
        show: () => checkPermi(['system:menu:create']),
        handler: () => openForm('create')
      },
      {
        label: '刷新菜单缓存',
        type: 'default',
        plain: true,
        icon: 'ep:refresh',
        handler: refreshMenu
      }
    ],
    api: {
      getList: async (params: any) => {
        // 根据左侧树的选择和搜索条件过滤本地数据
        let filteredData = filterMenuData(allMenuList.value, params.parentId)
        filteredData = applySearchFilters(filteredData, params)

        return {
          list: filteredData,
          total: filteredData.length
        }
      }
    },
    queryParams,
    onSelectionChange: (selection: any[]) => {
      // 处理选择变化
    }
  })
)

/** 查询列表 - 由TableList组件内部管理，这里只提供方法供其他组件调用 */
const getList = () => {
  tableListRef.value?.getList()
}

/** 刷新菜单缓存按钮操作 */
const refreshMenu = async () => {
  try {
    await message.confirm('即将更新缓存刷新浏览器！', '刷新菜单缓存')
    // 清空，从而触发刷新
    wsCache.delete(CACHE_KEY.USER)
    wsCache.delete(CACHE_KEY.ROLE_ROUTERS)
    // 刷新浏览器
    location.reload()
  } catch {}
}

/** 处理菜单被点击 */
const handleMenuNodeClick = async (row: any) => {
  // 直接更新TableList组件内部的queryParams
  const parentId = row === undefined ? undefined : row.id
  tableListRef.value?.updateQueryParams({ parentId })

  // 调用TableList组件的搜索方法（这会触发api.getList的重新调用）
  tableListRef.value?.handleSearch()
}

/** 切换左侧树显示/隐藏 */
const toggleTreeCollapse = () => {
  isTreeCollapsed.value = !isTreeCollapsed.value

  // 等待DOM更新后重新计算高度和按钮位置
  nextTick(() => {
    // 使用多次延时确保DOM完全更新
    setTimeout(() => {
      calculateTableHeight()
    }, 50)
    setTimeout(() => {
      calculateTableHeight()
    }, 200)
    setTimeout(() => {
      calculateTableHeight()
    }, 500)
  })
}

/** 计算表格高度和按钮位置 */
const calculateTableHeight = () => {
  nextTick(() => {
    const tableEl = document.querySelector('.table-wrap')
    if (tableEl) {
      tableHeight.value = tableEl.offsetHeight
    }

    // 重新计算按钮位置
    const tableWrapEl = document.querySelector('.table-wrap')
    const tableColEl = document.querySelector('.table-col')

    if (tableWrapEl && tableColEl) {
      if (isTreeCollapsed.value) {
        // 左侧树隐藏时，按钮在表格容器内左侧5px
        buttonLeftPosition.value = 5
      } else {
        // 左侧树显示时，按钮在表格列容器的最左边缘
        const tableColRect = tableColEl.getBoundingClientRect()
        const tableWrapRect = tableWrapEl.getBoundingClientRect()
        const relativeLeft = tableColRect.left - tableWrapRect.left
        buttonLeftPosition.value = Math.max(relativeLeft - 5, 0)
      }
    } else {
      // 回退方案
      buttonLeftPosition.value = isTreeCollapsed.value ? 5 : 0
    }
  })
}

/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number, parentId?: number) => {
  formRef.value.open(type, id, parentId)
}

/** 删除按钮操作 */
const handleDelete = async (id: number) => {
  try {
    // 删除的二次确认
    await message.delConfirm()
    // 发起删除
    await MenuApi.deleteMenu(id)
    message.success(t('common.delSuccess'))
    // 刷新列表
    handleRefresh()
  } catch {}
}

/** 开启/关闭菜单的状态 */
const handleStatusChanged = async (menu: MenuVO, val: number) => {
  const oldStaus = menu.status
  // 1. 标记 menu.id 更新中
  menuStatusUpdating.value[menu.id] = true
  try {
    // 2. 发起更新状态
    menu.status = val
    await MenuApi.updateMenu(menu)
    // 刷新列表
    // handleRefresh()
  } finally {
    // 3. 标记 menu.id 更新完成
    menuStatusUpdating.value[menu.id] = false
    menu.status = oldStaus
  }
}

/** 刷新列表 */
const handleRefresh = () => {
  tableListRef.value?.getList()
}

/** 初始化 */
onMounted(async () => {
  // 先加载完整的菜单数据（用于后续的树节点点击过滤）
  try {
    const data = await MenuApi.getMenuList()
    allMenuList.value = handleTree(data)
  } catch (error) {
    console.error('加载菜单数据失败:', error)
  }

  // 不调用 getList()，等待用户点击左侧树节点后再加载数据

  // 初始计算高度和按钮位置
  setTimeout(() => {
    calculateTableHeight()
  }, 800) // 给表格渲染更多时间

  setTimeout(() => {
    calculateTableHeight()
  }, 1500) // 二次计算确保准确

  // 监听窗口大小变化，重新计算高度
  window.addEventListener('resize', () => {
    setTimeout(calculateTableHeight, 300)
  })
})

// 监听isTreeCollapsed变化，重新计算高度和按钮位置
watch(isCollapsed, () => {
  nextTick(() => {
    setTimeout(() => {
      calculateTableHeight()
    }, 200)
  })
})
</script>

<style scoped>
.menu-management-container {
  position: relative;
  display: flex;
  gap: 12px;
  width: 100%;
}
.no-gap {
  gap: 0 !important;
}

.menu-tree-col {
  flex: 0 0 16.666667%; /* 对应原来span=4的宽度 (4/24) */
  transition:
    flex 0.3s ease,
    opacity 0.3s ease,
    margin-right 0.3s ease;
  position: relative;
  min-width: 0;
  min-height: 600px;
  overflow: hidden;
  border-radius: 8px;
  background-color: #fff;
  box-shadow:
    0 1px 2px 0 rgba(0, 0, 0, 0.03),
    0 1px 6px -1px rgba(0, 0, 0, 0.02),
    0 2px 4px 0 rgba(0, 0, 0, 0.02);
  padding: 10px;
}

.menu-tree-col.tree-collapsed {
  flex: 0 0 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
  padding: 0;
}

.menu-tree-content {
  min-height: 600px;
  transition: height 0.3s ease;
}

.table-col {
  flex: 1;
  transition: flex 0.3s ease;
  min-width: 0;
}

.table-wrap {
  position: relative;
}

.tree-toggle-btn {
  position: absolute;
  transform: translateX(-50%);
  width: 30px;
  height: 30px;
  background-color: #fff;
  color: rgba(0, 0, 0, 0.88);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 100;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  transition: all 0.3s ease;
  border: 2px solid white;
}

.tree-toggle-btn:hover {
  transform: translateX(-50%) scale(1.1);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

/* 响应式适配 */
@media (max-width: 400px) {
  .menu-management-container {
    flex-direction: column;
  }

  .menu-tree-col {
    flex: 0 0 auto;
    width: 100%;
  }

  .menu-tree-col.tree-collapsed {
    height: 0;
    margin-right: 0;
    margin-bottom: 0;
  }

  .table-col {
    flex: 1;
  }

  .tree-toggle-btn {
    left: -10px;
    width: 25px;
    height: 25px;
  }

  .tree-toggle-btn.collapsed {
    left: 10px;
  }
}

/* 平滑过渡效果 */
.menu-tree-col :deep(.content-wrap) {
  transition: all 0.3s ease;
}

.table-col :deep(.content-wrap) {
  transition: all 0.3s ease;
}
</style>
