<template>
  <div class="menu-management p-1 bg-gray-50 h-screen flex flex-col">
    <!-- 搜索表单和菜单表格 -->
    <div class="bg-white rounded-lg shadow-sm border border-gray-100 flex-1 flex flex-col overflow-hidden">
      <!-- 搜索表单 -->
      <div class="px-4 py-2 border-b border-gray-100">
        <n-form
          ref="searchFormRef"
          :model="searchForm"
          label-placement="left"
          label-width="auto"
          class="search-form"
        >
          <n-grid :cols="6" :x-gap="8" :y-gap="4">
            <n-grid-item>
              <n-form-item label="菜单名称" path="menuName">
                <n-input
                  v-model:value="searchForm.menuName"
                  placeholder="请输入菜单名称"
                  clearable
                  @keydown.enter="handleSearch"
                />
              </n-form-item>
            </n-grid-item>

            <n-grid-item>
              <n-form-item label="权限标识" path="auth">
                <n-input
                  v-model:value="searchForm.auth"
                  placeholder="请输入权限标识"
                  clearable
                  @keydown.enter="handleSearch"
                />
              </n-form-item>
            </n-grid-item>

            <n-grid-item>
              <n-form-item label="菜单状态" path="menuStatus">
                <n-select
                  v-model:value="searchForm.menuStatus"
                  placeholder="请选择菜单状态"
                  clearable
                  :options="[
                    { label: '启用', value: '0' },
                    { label: '停用', value: '1' },
                  ]"
                />
              </n-form-item>
            </n-grid-item>

            <n-grid-item>
              <n-form-item label="" path="">
                <NSpace>
                  <NButton type="primary" @click="handleSearch">
                    <template #icon>
                      <NIcon><icon-park-outline:search /></NIcon>
                    </template>
                    搜索
                  </NButton>
                  <NButton @click="handleReset">
                    <template #icon>
                      <NIcon><icon-park-outline:refresh /></NIcon>
                    </template>
                    重置
                  </NButton>
                </NSpace>
              </n-form-item>
            </n-grid-item>
          </n-grid>
        </n-form>
      </div>

      <!-- 表格头部操作栏 -->
      <div class="flex items-center justify-between px-4 py-2 border-b border-gray-100">
        <div class="flex items-center gap-4">
          <NButton v-permission="PERMISSIONS.MENU.ADD" type="primary" class="px-6 flex items-center" @click="handleAdd">
            <template #icon>
              <NIcon class="mr-1" style="transform: translateY(-1px)">
                <icon-park-outline:plus />
              </NIcon>
            </template>
            新增
          </NButton>

          <NButton
            v-permission="PERMISSIONS.MENU.DELETE"
            type="error"
            :disabled="selectedRows.length === 0"
            class="px-6 flex items-center"
            @click="handleBatchDelete"
          >
            <template #icon>
              <NIcon class="mr-1" style="transform: translateY(-1px)">
                <icon-park-outline:delete />
              </NIcon>
            </template>
            删除
          </NButton>

          <NButton class="px-6 flex items-center" @click="handleExpandToggle">
            <template #icon>
              <NIcon class="mr-1" style="transform: translateY(-1px)">
                <icon-park-outline:expand-up v-if="isAllExpanded" />
                <icon-park-outline:expand-down v-else />
              </NIcon>
            </template>
            {{ isAllExpanded ? '全部折叠' : '全部展开' }}
          </NButton>
        </div>

        <div class="flex items-center gap-2">
          <NButton type="tertiary" @click="handleRefresh">
            <template #icon>
              <NIcon><icon-park-outline:refresh /></NIcon>
            </template>
          </NButton>
        </div>
      </div>

      <!-- 表格内容 -->
      <div class="table-wrapper flex-1 overflow-auto pt-4">
        <!-- 数据表格 -->
        <n-data-table
          v-if="tableData.length > 0 || loading"
          v-model:expanded-row-keys="expandedKeys"
          :columns="columns"
          :data="tableData"
          :loading="loading"
          :row-key="(row: MenuVo) => row.menuId"
          :bordered="false"
          :single-line="false"
          children-key="children"
          size="large"
          class="custom-table"
          @update:checked-row-keys="handleRowSelectionChange"
          @update:expanded-row-keys="handleExpandedKeysChange"
        />

        <!-- 空状态 -->
        <CoiEmpty
          v-else
          :type="getEmptyType()"
          :title="getEmptyTitle()"
          :description="getEmptyDescription()"
          :show-action="true"
          :action-text="getEmptyActionText()"
          size="medium"
          @action="handleEmptyAction"
        >
          <template #action>
            <NButton
              type="primary"
              size="medium"
              round
              class="coi-empty__action-btn"
              @click="handleEmptyAction"
            >
              <template #icon>
                <NIcon>
                  <icon-park-outline:refresh v-if="hasSearchConditions()" />
                  <icon-park-outline:plus v-else />
                </NIcon>
              </template>
              {{ getEmptyActionText() }}
            </NButton>
          </template>
        </CoiEmpty>
      </div>
    </div>

    <!-- 菜单表单弹框 -->
    <CoiDialog
      ref="menuDialogRef"
      :title="modalTitle"
      :width="800"
      height="auto"
      confirm-text="确定"
      cancel-text="取消"
      @coi-confirm="handleSubmit"
      @coi-cancel="handleCancel"
    >
      <template #content>
        <div class="px-3 py-2">
          <n-form
            ref="formRef"
            :model="formData"
            :rules="rules"
            label-placement="left"
            label-width="90px"
            require-mark-placement="right-hanging"
            class="compact-form"
          >
            <!-- 菜单上级 -->
            <n-form-item label="菜单上级" path="parentId" class="mb-2">
              <n-popover
                ref="parentSelectorRef"
                trigger="click"
                placement="bottom-start"
                :show-arrow="false"
                style="padding: 0"
                :width="600"
              >
                <template #trigger>
                  <n-input
                    :value="getSelectedMenuText()"
                    placeholder="最顶级菜单"
                    readonly
                    class="w-full cursor-pointer"
                    clearable
                    @clear="handleClearParent"
                  >
                    <template #suffix>
                      <NIcon>
                        <icon-park-outline:down />
                      </NIcon>
                    </template>
                  </n-input>
                </template>
                <template #default>
                  <div class="menu-selector">
                    <n-grid :cols="2" :x-gap="0">
                      <!-- 一级菜单（包含最顶级菜单） -->
                      <n-grid-item>
                        <div class="menu-column">
                          <div class="column-header">
                            一级菜单
                          </div>
                          <div class="menu-options">
                            <!-- 最顶级菜单选项 -->
                            <div
                              class="menu-option"
                              :class="{ active: formData.parentId === '0' }"
                              :style="formData.parentId === '0' ? { color: themeColors.primary, fontWeight: '500' } : {}"
                              @click="handleSelectParent('0', '最顶级菜单')"
                            >
                              <n-radio
                                :checked="formData.parentId === '0'"
                                style="pointer-events: none;"
                              />
                              <span
                                class="option-text"
                                :style="formData.parentId === '0' ? { color: themeColors.primary, fontWeight: '500', display: 'inline-block' } : {}"
                              >
                                最顶级菜单
                              </span>
                            </div>

                            <!-- 分隔线 -->
                            <div class="menu-separator" />

                            <!-- 其他一级菜单 -->
                            <div
                              v-for="menu in topLevelMenus"
                              :key="menu.value"
                              class="menu-option"
                              :class="{
                                active: formData.parentId === menu.value,
                                hoverable: menu.children?.length > 0,
                              }"
                              :style="formData.parentId === menu.value ? { color: themeColors.primary, fontWeight: '500' } : {}"
                              @click="handleSelectParent(menu.value, menu.label)"
                              @mouseenter="handleMenuHover(menu)"
                            >
                              <n-radio
                                :checked="formData.parentId === menu.value"
                                style="pointer-events: none;"
                              />
                              <span
                                class="option-text"
                                :style="formData.parentId === menu.value ? { color: themeColors.primary, fontWeight: '500', display: 'inline-block' } : {}"
                              >
                                {{ menu.label }}
                              </span>
                              <span
                                v-if="menu.children?.length"
                                class="children-count"
                                :style="formData.parentId === menu.value ? { color: themeColors.primary, opacity: '0.7' } : {}"
                              >
                                ({{ menu.children.length }})
                              </span>
                              <NIcon v-if="menu.children?.length" class="expand-icon">
                                <icon-park-outline:right />
                              </NIcon>
                            </div>
                          </div>
                        </div>
                      </n-grid-item>

                      <!-- 二级菜单 -->
                      <n-grid-item>
                        <div class="menu-column">
                          <div class="column-header">
                            二级菜单
                          </div>
                          <div class="menu-options">
                            <div
                              v-for="submenu in currentSubMenus"
                              :key="submenu.value"
                              class="menu-option"
                              :class="{ active: formData.parentId === submenu.value }"
                              :style="formData.parentId === submenu.value ? { color: themeColors.primary, fontWeight: '500' } : {}"
                              @click="handleSelectParent(submenu.value, submenu.label)"
                            >
                              <n-radio
                                :checked="formData.parentId === submenu.value"
                                style="pointer-events: none;"
                              />
                              <span
                                class="option-text"
                                :style="formData.parentId === submenu.value ? { color: themeColors.primary, fontWeight: '500' } : {}"
                              >
                                {{ submenu.label }}
                              </span>
                            </div>
                          </div>
                        </div>
                      </n-grid-item>
                    </n-grid>
                  </div>
                </template>
              </n-popover>
            </n-form-item>

            <!-- 菜单类型 -->
            <n-form-item label="菜单类型" path="menuType" class="mb-2">
              <n-radio-group
                v-model:value="formData.menuType"
                @update:value="handleMenuTypeChange"
              >
                <n-radio value="1">
                  目录
                </n-radio>
                <n-radio value="2">
                  菜单
                </n-radio>
                <n-radio value="3">
                  按钮
                </n-radio>
              </n-radio-group>
            </n-form-item>

            <!-- 菜单图标 -->
            <n-form-item v-if="formData.menuType !== '3'" label="菜单图标" path="icon" class="mb-2">
              <IconSelect v-model:value="formData.icon" />
            </n-form-item>

            <!-- 菜单名称 + 显示排序 -->
            <n-grid :cols="2" :x-gap="10" class="mb-2">
              <n-grid-item>
                <n-form-item label="菜单名称" path="menuName">
                  <n-input
                    v-model:value="formData.menuName"
                    placeholder="请输入菜单名称"
                  />
                </n-form-item>
              </n-grid-item>
              <n-grid-item>
                <n-form-item label="显示排序" path="sorted">
                  <n-input-number
                    v-model:value="formData.sorted"
                    :min="0"
                    placeholder="0"
                    class="w-full"
                  />
                </n-form-item>
              </n-grid-item>
            </n-grid>

            <!-- 英文菜单 + 页面路径 -->
            <n-grid :cols="2" :x-gap="10" class="mb-2">
              <n-grid-item v-if="formData.menuType !== '3'">
                <n-form-item label="英文菜单" path="enName">
                  <n-input
                    v-model:value="formData.enName"
                    placeholder="请输入英文菜单"
                  />
                </n-form-item>
              </n-grid-item>
              <n-grid-item v-if="formData.menuType === '2'">
                <n-form-item label="页面路径" path="component">
                  <n-input
                    v-model:value="formData.component"
                    placeholder="例如：system/user/index"
                  />
                </n-form-item>
              </n-grid-item>
            </n-grid>

            <!-- 是否隐藏 + 权限字符 -->
            <n-grid :cols="2" :x-gap="10" class="mb-2">
              <n-grid-item>
                <n-form-item label="是否隐藏" path="isHide">
                  <n-radio-group v-model:value="formData.isHide">
                    <n-radio value="0">
                      是
                    </n-radio>
                    <n-radio value="1">
                      否
                    </n-radio>
                  </n-radio-group>
                </n-form-item>
              </n-grid-item>
              <n-grid-item>
                <n-form-item label="权限字符" path="auth">
                  <n-input
                    v-model:value="formData.auth"
                    placeholder="权限字符[system:user:list]"
                  />
                </n-form-item>
              </n-grid-item>
            </n-grid>

            <!-- 菜单类型为"菜单"时显示的字段 -->
            <template v-if="formData.menuType === '2'">
              <!-- 路由名称 + 路由Path -->
              <n-grid :cols="2" :x-gap="10" class="mb-2">
                <n-grid-item>
                  <n-form-item label="路由名称" path="name">
                    <n-input
                      v-model:value="formData.name"
                      placeholder="例如：userPage[唯一]"
                    />
                  </n-form-item>
                </n-grid-item>
                <n-grid-item>
                  <n-form-item label="路由Path" path="path">
                    <n-input
                      v-model:value="formData.path"
                      placeholder="例如：/system/user[唯一]"
                    />
                  </n-form-item>
                </n-grid-item>
              </n-grid>

              <!-- 是否缓存 -->
              <n-form-item label="是否缓存" path="isKeepAlive" class="mb-2">
                <n-radio-group v-model:value="formData.isKeepAlive">
                  <n-radio value="0">
                    是
                  </n-radio>
                  <n-radio value="1">
                    否
                  </n-radio>
                </n-radio-group>
              </n-form-item>

              <!-- 是否展开 + 是否固钉 -->
              <n-grid :cols="2" :x-gap="10" class="mb-2">
                <n-grid-item>
                  <n-form-item label="是否展开" path="isSpread">
                    <n-radio-group v-model:value="formData.isSpread">
                      <n-radio value="0">
                        是
                      </n-radio>
                      <n-radio value="1">
                        否
                      </n-radio>
                    </n-radio-group>
                  </n-form-item>
                </n-grid-item>
                <n-grid-item>
                  <n-form-item label="是否固钉" path="isAffix">
                    <n-radio-group v-model:value="formData.isAffix">
                      <n-radio value="0">
                        是
                      </n-radio>
                      <n-radio value="1">
                        否
                      </n-radio>
                    </n-radio-group>
                  </n-form-item>
                </n-grid-item>
              </n-grid>
            </template>

            <!-- 目录类型时显示是否展开 -->
            <template v-if="formData.menuType === '1'">
              <n-form-item label="是否展开" path="isSpread" class="mb-2">
                <n-radio-group v-model:value="formData.isSpread">
                  <n-radio value="0">
                    是
                  </n-radio>
                  <n-radio value="1">
                    否
                  </n-radio>
                </n-radio-group>
              </n-form-item>
            </template>

            <!-- 外链地址 -->
            <n-form-item label="外链地址" path="isLink" class="mb-2">
              <n-input
                v-model:value="formData.isLink"
                placeholder="请输入外链地址[输入值则判断为外链地址]"
                class="w-full"
              />
            </n-form-item>
          </n-form>
        </div>
      </template>
    </CoiDialog>
  </div>
</template>

<script setup lang="ts">
import { computed, h, nextTick, onMounted, ref } from 'vue'
import type { DataTableColumns, FormInst, FormRules } from 'naive-ui'
import { NButton, NIcon, NPopconfirm, NSpace, NSwitch, NTag, NTooltip } from 'naive-ui'
import IconParkOutlineDelete from '~icons/icon-park-outline/delete'
import IconParkOutlineEdit from '~icons/icon-park-outline/edit'
import IconParkOutlinePlus from '~icons/icon-park-outline/plus'
import CoiDialog from '@/components/common/CoiDialog.vue'
import CoiEmpty from '@/components/common/CoiEmpty.vue'
import CoiIcon from '@/components/common/CoiIcon.vue'
import IconSelect from '@/components/common/IconSelect.vue'
import { PERMISSIONS } from '@/constants/permissions'
import { coiMsgBox, coiMsgError, coiMsgSuccess } from '@/utils/coi'
import {
  addMenu,
  batchDeleteMenu,
  deleteMenu,
  getMenuList,
  updateMenu,
  updateMenuSpread,
  updateMenuStatus,
} from '@/service/api/system/menu'
import type { MenuCascaderBo, MenuForm, MenuQueryBo, MenuVo } from '@/service/api/system/menu'
import { useAppStore } from '@/store/app'
import { colord } from 'colord'

// 应用状态
const appStore = useAppStore()

// 主题色计算属性
const themeColors = computed(() => {
  const primary = appStore.primaryColor
  return {
    primary,
    primaryHover: colord(primary).lighten(0.1).toHex(),
    primaryLight: colord(primary).lighten(0.3).toHex(),
    primaryLighter: colord(primary).lighten(0.4).toHex(),
  }
})

// 搜索表单
const searchFormRef = ref<FormInst>()
const searchForm = ref<MenuQueryBo>({})

// 表格数据
const tableData = ref<MenuVo[]>([])
const loading = ref(false)
const selectedRows = ref<MenuVo[]>([])
const expandedKeys = ref<string[]>([])
const isAllExpanded = ref(true)

// 弹框相关
const menuDialogRef = ref()
const formRef = ref<FormInst>()
const modalTitle = ref('')
const isEdit = ref(false)

// 表单数据
const formData = ref<MenuForm>({
  menuName: '',
  enName: '',
  parentId: '0', // 改为字符串
  menuType: '1',
  path: '',
  name: '',
  component: '',
  icon: '',
  auth: '',
  menuStatus: '0',
  activeMenu: '',
  isHide: '1',
  isLink: '',
  isKeepAlive: '1',
  isFull: '1',
  isAffix: '1',
  isSpread: '1',
  sorted: 0,
  remark: '',
})

// 级联选择器数据
const menuCascaderOptions = ref<MenuCascaderBo[]>([])

// 自定义菜单选择器数据
const topLevelMenus = ref<MenuCascaderBo[]>([])
const currentSubMenus = ref<MenuCascaderBo[]>([])
const selectedMenuText = ref('')
const parentSelectorRef = ref()

// 表单校验规则
const rules: FormRules = {
  menuName: [
    { required: true, message: '请输入菜单名称', trigger: 'blur' },
  ],
  parentId: [
    {
      required: false, // 改为非必填，因为'0'是有效的顶级菜单值
      type: 'string',
      message: '请选择上级菜单',
      trigger: ['change', 'blur'],
      validator: (rule: any, value: any, callback: any) => {
        // parentId 应该是一个有效的字符串
        if (typeof value === 'string' && value.length > 0) {
          callback()
        }
        else {
          callback(new Error('请选择上级菜单'))
        }
      },
    },
  ],
  menuType: [
    { required: true, message: '请选择菜单类型', trigger: 'change' },
  ],
  sorted: [
    { required: true, type: 'number', message: '请输入显示顺序', trigger: 'blur' },
  ],
  path: [
    {
      required: false,
      message: '请输入路由地址',
      trigger: 'blur',
      validator: (rule: any, value: any, callback: any) => {
        // 获取当前表单数据
        const currentMenuType = formData.value.menuType
        // 只有菜单类型需要路由地址
        if (currentMenuType === '2' && (!value || value.trim() === '')) {
          callback(new Error('请输入路由地址'))
        }
        else {
          callback()
        }
      },
    },
  ],
  auth: [
    { required: true, message: '请输入权限标识', trigger: 'blur' },
  ],
}

// 表格列定义
const columns: DataTableColumns<MenuVo> = [
  {
    type: 'selection',
    width: 50,
  },
  {
    title: '序号',
    key: 'index',
    width: 80,
    align: 'center',
    render: (row) => {
      return (row as any).globalIndex || '-'
    },
  },
  {
    title: '菜单名称',
    key: 'menuName',
    width: 150,
    align: 'center',
    ellipsis: {
      tooltip: true,
    },
    tree: true,
  },
  {
    title: '英文名称',
    key: 'enName',
    width: 150,
    align: 'center',
    ellipsis: {
      tooltip: true,
    },
    render: row => row.enName || '-',
  },
  {
    title: '菜单类型',
    key: 'menuType',
    width: 100,
    align: 'center',
    render: (row) => {
      const typeMap = {
        1: { label: '目录', color: 'primary' },
        2: { label: '菜单', color: 'info' },
        3: { label: '按钮', color: 'warning' },
      }
      const type = typeMap[Number(row.menuType) as keyof typeof typeMap]
      return h(NTag, { type: type.color }, { default: () => type.label })
    },
  },
  {
    title: '展开/折叠',
    key: 'isSpread',
    width: 100,
    align: 'center',
    render: (row) => {
      if (row.menuType === '3')
        return '-' // 按钮类型不显示
      return h(NSwitch, {
        value: row.isSpread === '0',
        checkedText: '展开',
        uncheckedText: '收起',
        onUpdateValue: value => handleSpreadChange(row, value ? '0' : '1'),
      })
    },
  },
  {
    title: '图标',
    key: 'icon',
    width: 80,
    align: 'center',
    render: (row) => {
      return row.icon ? h('div', { class: 'flex justify-center' }, h(CoiIcon, { icon: row.icon, size: 18 })) : '-'
    },
  },
  {
    title: '权限标识',
    key: 'auth',
    width: 200,
    align: 'center',
    ellipsis: {
      tooltip: true,
    },
    render: row => row.auth || '-',
  },
  {
    title: '页面路径',
    key: 'component',
    width: 200,
    align: 'center',
    ellipsis: {
      tooltip: true,
    },
    render: row => row.component || '-',
  },
  {
    title: '路由地址',
    key: 'path',
    width: 180,
    align: 'center',
    ellipsis: {
      tooltip: true,
    },
    render: row => row.path || '-',
  },
  {
    title: '路由名称',
    key: 'name',
    width: 130,
    align: 'center',
    ellipsis: {
      tooltip: true,
    },
    render: row => row.name || '-',
  },
  {
    title: '是否隐藏',
    key: 'isHide',
    width: 100,
    align: 'center',
    render: (row) => {
      return h(NTag, {
        type: row.isHide === '0' ? 'error' : 'success',
      }, {
        default: () => row.isHide === '0' ? '隐藏' : '显示',
      })
    },
  },
  {
    title: '排序',
    key: 'sorted',
    width: 80,
    align: 'center',
  },
  {
    title: '菜单状态',
    key: 'menuStatus',
    width: 100,
    align: 'center',
    render: (row) => {
      return h(NSwitch, {
        value: row.menuStatus === '0',
        onUpdateValue: value => handleStatusChange(row, value ? '0' : '1'),
      })
    },
  },
  {
    title: '操作',
    key: 'actions',
    width: 160,
    align: 'center',
    fixed: 'right',
    render: (row) => {
      const buttons = []

      // 新增子菜单按钮
      if (row.menuType !== '3') {
        buttons.push(h(NTooltip, {
          trigger: 'hover',
        }, {
          default: () => '新增子菜单',
          trigger: () => h(NButton, {
            type: 'info',
            size: 'medium',
            circle: true,
            class: 'action-btn action-btn-info',
            onClick: () => handleAddChild(row),
          }, {
            icon: () => h(NIcon, { size: 18 }, { default: () => h(IconParkOutlinePlus) }),
          }),
        }))
      }

      // 编辑按钮
      buttons.push(h(NTooltip, {
        trigger: 'hover',
      }, {
        default: () => '编辑',
        trigger: () => h(NButton, {
          type: 'primary',
          size: 'medium',
          circle: true,
          class: 'action-btn action-btn-edit',
          onClick: () => handleEdit(row),
        }, {
          icon: () => h(NIcon, { size: 18 }, { default: () => h(IconParkOutlineEdit) }),
        }),
      }))

      // 删除按钮
      buttons.push(h(NPopconfirm, {
        onPositiveClick: () => handleDelete(row.menuId),
        negativeText: '取消',
        positiveText: '确定',
      }, {
        default: () => '确定删除此菜单吗？',
        trigger: () => h(NTooltip, {
          trigger: 'hover',
        }, {
          default: () => '删除',
          trigger: () => h(NButton, {
            type: 'error',
            size: 'medium',
            circle: true,
            class: 'action-btn action-btn-delete',
          }, {
            icon: () => h(NIcon, { size: 18 }, { default: () => h(IconParkOutlineDelete) }),
          }),
        }),
      }))

      return h('div', { class: 'flex items-center justify-center gap-2' }, buttons)
    },
  },
]

// 获取菜单列表
async function getMenuData() {
  try {
    loading.value = true
    const { data } = await getMenuList(searchForm.value)
    tableData.value = buildMenuTree(data)
    // 构建树形结构后，按显示顺序添加序号
    addTreeIndexToMenus(tableData.value)

    // 根据 isSpread 字段设置初始展开状态
    nextTick(() => {
      const initialExpandedKeys = getInitialExpandedKeys(tableData.value)
      expandedKeys.value = initialExpandedKeys

      // 强制更新全局状态
      updateGlobalExpandedState(initialExpandedKeys, true)
    })
  }
  catch {
    coiMsgError('获取菜单列表失败')
  }
  finally {
    loading.value = false
  }
}

// 为树形菜单添加按显示顺序的序号
function addTreeIndexToMenus(menus: MenuVo[]) {
  let globalIndex = 1

  function addIndexRecursively(menuList: MenuVo[]) {
    // 按sorted字段排序
    const sortedMenus = [...menuList].sort((a, b) => a.sorted - b.sorted)

    for (const menu of sortedMenus) {
      // 给当前菜单添加序号
      ;(menu as any).globalIndex = globalIndex++

      // 如果有子菜单，递归处理
      if (menu.children && menu.children.length > 0) {
        addIndexRecursively(menu.children)
      }
    }
  }

  addIndexRecursively(menus)
}

// 构建菜单树
function buildMenuTree(menus: MenuVo[]): MenuVo[] {
  const menuMap = new Map<number, MenuVo>()
  const result: MenuVo[] = []

  // 先将所有菜单放入map
  menus.forEach((menu) => {
    menuMap.set(menu.menuId, { ...menu, children: [] })
  })

  // 构建树形结构
  menus.forEach((menu) => {
    const currentMenu = menuMap.get(menu.menuId)!
    if (menu.parentId === 0) {
      result.push(currentMenu)
    }
    else {
      const parent = menuMap.get(menu.parentId)
      if (parent) {
        parent.children = parent.children || []
        parent.children.push(currentMenu)
      }
    }
  })

  return result
}

// 获取所有菜单ID
function getAllMenuIds(menus: MenuVo[]): string[] {
  const ids: string[] = []
  function traverse(nodes: MenuVo[]) {
    nodes.forEach((node) => {
      ids.push(node.menuId) // 直接使用字符串，无需转换
      if (node.children?.length) {
        traverse(node.children)
      }
    })
  }
  traverse(menus)
  return ids
}

// 根据 isSpread 字段获取初始展开的菜单ID
function getInitialExpandedKeys(menus: MenuVo[]): string[] {
  const expandedIds: string[] = []
  function traverse(nodes: MenuVo[]) {
    nodes.forEach((node) => {
      // isSpread === '0' 表示默认展开
      if (node.isSpread === '0') {
        expandedIds.push(node.menuId) // 直接使用字符串，无需转换
      }
      if (node.children?.length) {
        traverse(node.children)
      }
    })
  }
  traverse(menus)
  return expandedIds
}

// 更新本地数据中指定菜单项的 isSpread 状态
function updateMenuSpreadInData(menus: MenuVo[], menuId: string, isSpread: string) {
  function traverse(nodes: MenuVo[]) {
    for (const node of nodes) {
      if (node.menuId === menuId) {
        node.isSpread = isSpread
        return true
      }
      if (node.children?.length && traverse(node.children)) {
        return true
      }
    }
    return false
  }
  traverse(menus)
}

// 更新本地数据中指定菜单项的 menuStatus 状态
function updateMenuStatusInData(menus: MenuVo[], menuId: string, menuStatus: string) {
  function traverse(nodes: MenuVo[]) {
    for (const node of nodes) {
      if (node.menuId === menuId) {
        node.menuStatus = menuStatus
        return true
      }
      if (node.children?.length && traverse(node.children)) {
        return true
      }
    }
    return false
  }
  traverse(menus)
}

// 获取级联选择器数据
async function getMenuCascaderData() {
  try {
    // 使用菜单列表接口获取完整的树形数据，这样更准确
    const { data: menuListData } = await getMenuList({})

    // 构建树形结构
    const treeData = buildMenuTree(menuListData)

    // 转换为级联选择器格式
    const cascaderData = convertToMenuCascader(treeData)

    menuCascaderOptions.value = [
      { value: '0', label: '主目录', children: cascaderData },
    ]

    // 顶级菜单就是树形数据的第一层
    topLevelMenus.value = cascaderData
  }
  catch {
    coiMsgError('获取菜单级联数据失败')
  }
}

// 转换菜单数据为级联选择器格式
function convertToMenuCascader(menuTree: MenuVo[]): MenuCascaderBo[] {
  return menuTree.map(menu => ({
    value: menu.menuId,
    label: menu.menuName,
    children: menu.children && menu.children.length > 0
      ? convertToMenuCascader(menu.children)
      : undefined,
  }))
}

// 获取选中菜单的显示文本
function getSelectedMenuText() {
  if (formData.value.parentId === '0') {
    return '最顶级菜单'
  }

  // 先在顶级菜单中查找
  const topMenu = topLevelMenus.value.find(menu => menu.value === formData.value.parentId)
  if (topMenu) {
    return topMenu.label
  }

  // 再在子菜单中查找
  for (const menu of topLevelMenus.value) {
    if (menu.children?.length) {
      const subMenu = menu.children.find(child => child.value === formData.value.parentId)
      if (subMenu) {
        return subMenu.label
      }
    }
  }

  return selectedMenuText.value
}

// 处理选择父菜单
function handleSelectParent(value: string, label: string) {
  formData.value.parentId = value
  selectedMenuText.value = label
  // 关闭弹窗
  parentSelectorRef.value?.setShow(false)

  // 手动触发 parentId 字段的验证
  nextTick(() => {
    formRef.value?.validate(['parentId']).catch(() => {
      // 忽略验证错误，只是为了触发验证状态更新
    })
  })
}

// 处理清除父菜单选择
function handleClearParent() {
  formData.value.parentId = '0'
  selectedMenuText.value = ''
  currentSubMenus.value = []

  // 手动触发 parentId 字段的验证
  nextTick(() => {
    formRef.value?.validate(['parentId']).catch(() => {
      // 忽略验证错误，只是为了触发验证状态更新
    })
  })
}

// 处理菜单悬停，显示子菜单
function handleMenuHover(menu: MenuCascaderBo) {
  if (menu.children?.length) {
    currentSubMenus.value = menu.children
  }
  else {
    currentSubMenus.value = []
  }
}

// 搜索
function handleSearch() {
  // 搜索时使用默认的展开状态（基于isSpread字段）
  getMenuData()
}

// 重置
function handleReset() {
  searchForm.value = {}
  // 重置时也使用默认的展开状态
  handleSearch()
}

// 刷新
function handleRefresh() {
  handleSearch()
}

// 全局展开/折叠切换（基于isSpread状态智能操作）
function handleExpandToggle() {
  if (isAllExpanded.value) {
    // 全部折叠：恢复到基于isSpread字段的默认展开状态
    const shouldExpandIds = getInitialExpandedKeys(tableData.value)
    expandedKeys.value = [...shouldExpandIds]
    isAllExpanded.value = false
  }
  else {
    // 全部展开：展开所有菜单项
    const allIds = getAllMenuIds(tableData.value)
    expandedKeys.value = [...allIds]
    isAllExpanded.value = true
  }
}

// 统一更新全局展开状态的函数（仅在必要时自动更新）
function updateGlobalExpandedState(keys: string[], forceUpdate = false) {
  if (forceUpdate) {
    const allIds = getAllMenuIds(tableData.value)
    isAllExpanded.value = keys.length === allIds.length
  }
}

// 展开键变化
function handleExpandedKeysChange(_keys: string[]) {
  // 使用 v-model 后，expandedKeys 会自动更新
  // 对于全局按钮操作，状态已经在 handleExpandToggle 中设置，这里不需要自动更新
}

// 行选择变化
function handleRowSelectionChange(keys: string[]) {
  selectedRows.value = tableData.value.filter(item => keys.includes(item.menuId))
}

// 新增菜单
function handleAdd() {
  modalTitle.value = '新增菜单'
  isEdit.value = false
  resetFormData()
  menuDialogRef.value?.coiOpen()
}

// 设置父菜单显示文本的辅助函数
function setParentMenuText(parentId: string) {
  if (parentId === '0') {
    selectedMenuText.value = '最顶级菜单'
    return
  }

  // 在级联数据中查找父菜单名称
  function findMenuNameById(menus: MenuCascaderBo[], targetId: string): string | null {
    for (const menu of menus) {
      if (menu.value === targetId) {
        return menu.label
      }
      if (menu.children?.length) {
        const found = findMenuNameById(menu.children, targetId)
        if (found)
          return found
      }
    }
    return null
  }

  const parentMenuName = findMenuNameById(topLevelMenus.value, parentId)
  selectedMenuText.value = parentMenuName || `菜单ID: ${parentId}`
}

// 新增子菜单
function handleAddChild(parentMenu: MenuVo) {
  modalTitle.value = `新增${parentMenu.menuName}的子菜单`
  isEdit.value = false
  resetFormData()

  // 设置父菜单信息
  formData.value.parentId = parentMenu.menuId // 直接使用字符串，无需转换
  selectedMenuText.value = parentMenu.menuName // 设置显示文本

  // 根据父菜单类型智能设置子菜单默认类型
  if (parentMenu.menuType === '1') {
    // 目录的子菜单默认为菜单
    formData.value.menuType = '2'
  }
  else if (parentMenu.menuType === '2') {
    // 菜单的子菜单默认为按钮
    formData.value.menuType = '3'
    // 按钮类型默认隐藏
    formData.value.isHide = '0'
  }

  menuDialogRef.value?.coiOpen()
}

// 编辑菜单
function handleEdit(menu: MenuVo) {
  modalTitle.value = '编辑菜单'
  isEdit.value = true
  formData.value = {
    ...menu,
    sorted: Number(menu.sorted), // 确保 sorted 是数字类型
  }

  // 设置父菜单显示文本
  setParentMenuText(menu.parentId)

  menuDialogRef.value?.coiOpen()
}

// 删除菜单
async function handleDelete(menuId: string) {
  try {
    // 保存当前的展开状态
    const currentExpandedKeys = [...expandedKeys.value]
    const currentIsAllExpanded = isAllExpanded.value

    await deleteMenu(menuId)
    coiMsgSuccess('删除成功')
    await getMenuData()

    // 恢复之前的展开状态（排除已删除的项）
    nextTick(() => {
      const allIds = getAllMenuIds(tableData.value)
      expandedKeys.value = currentExpandedKeys.filter(id => allIds.includes(id))
      isAllExpanded.value = expandedKeys.value.length === allIds.length && currentIsAllExpanded
    })
  }
  catch {
    coiMsgError('删除失败')
  }
}

// 批量删除
async function handleBatchDelete() {
  if (selectedRows.value.length === 0) {
    coiMsgError('请选择要删除的菜单')
    return
  }

  try {
    await coiMsgBox('确定要删除选中的菜单吗？', '删除确认')

    // 保存当前的展开状态
    const currentExpandedKeys = [...expandedKeys.value]
    const currentIsAllExpanded = isAllExpanded.value

    const ids = selectedRows.value.map(item => item.menuId)
    await batchDeleteMenu(ids)
    coiMsgSuccess('删除成功')
    selectedRows.value = []
    await getMenuData()

    // 恢复之前的展开状态（排除已删除的项）
    nextTick(() => {
      const allIds = getAllMenuIds(tableData.value)
      expandedKeys.value = currentExpandedKeys.filter(id => allIds.includes(id))
      isAllExpanded.value = expandedKeys.value.length === allIds.length && currentIsAllExpanded
    })
  }
  catch {
    // 用户取消删除或删除失败
  }
}

// 状态变更
async function handleStatusChange(menu: MenuVo, status: string) {
  try {
    await updateMenuStatus(menu.menuId, status)

    // 更新本地数据的状态
    updateMenuStatusInData(tableData.value, menu.menuId, status)

    coiMsgSuccess('状态修改成功')
  }
  catch {
    coiMsgError('状态修改失败')
  }
}

// 展开状态变更
async function handleSpreadChange(menu: MenuVo, isSpread: string) {
  try {
    await updateMenuSpread(menu.menuId, isSpread)

    // 更新本地数据的 isSpread 状态
    updateMenuSpreadInData(tableData.value, menu.menuId, isSpread)

    // 同步更新UI展开状态
    const menuIdStr = menu.menuId // 直接使用字符串，无需转换
    if (isSpread === '0') {
      // 如果设置为展开，添加到展开列表
      if (!expandedKeys.value.includes(menuIdStr)) {
        expandedKeys.value.push(menuIdStr)
      }
    }
    else {
      // 如果设置为收起，从展开列表移除
      expandedKeys.value = expandedKeys.value.filter(id => id !== menuIdStr)
    }

    // 更新全局展开状态（单行操作需要强制更新）
    updateGlobalExpandedState(expandedKeys.value, true)
  }
  catch {
    coiMsgError('展开状态修改失败')
  }
}

// 菜单类型变化
function handleMenuTypeChange(value: string) {
  // 按钮类型默认隐藏
  if (value === '3') {
    formData.value.isHide = '0'
  }
  else {
    formData.value.isHide = '1'
  }
}

// 提交表单
async function handleSubmit() {
  try {
    await formRef.value?.validate()

    // 保存当前的展开状态
    const currentExpandedKeys = [...expandedKeys.value]
    const currentIsAllExpanded = isAllExpanded.value

    if (isEdit.value) {
      await updateMenu(formData.value)
      coiMsgSuccess('修改成功')
    }
    else {
      await addMenu(formData.value)
      coiMsgSuccess('新增成功')
    }

    menuDialogRef.value?.coiClose()
    await getMenuData()
    await getMenuCascaderData()

    // 恢复之前的展开状态
    nextTick(() => {
      expandedKeys.value = currentExpandedKeys
      isAllExpanded.value = currentIsAllExpanded
    })
  }
  catch (error) {
    if (error instanceof Error) {
      coiMsgError(error.message || '操作失败')
    }
  }
}

// 取消
function handleCancel() {
  menuDialogRef.value?.coiClose()
}

// 重置表单数据
function resetFormData() {
  formData.value = {
    menuName: '',
    enName: '',
    parentId: '0',
    menuType: '1',
    path: '',
    name: '',
    component: '',
    icon: '',
    auth: '',
    menuStatus: '0',
    activeMenu: '',
    isHide: '1',
    isLink: '',
    isKeepAlive: '1',
    isFull: '1',
    isAffix: '1',
    isSpread: '1',
    sorted: 0,
    remark: '',
  }
  // 重置父菜单显示文本
  selectedMenuText.value = ''
  // 重置子菜单选项
  currentSubMenus.value = []
}

// 空状态相关
function hasSearchConditions(): boolean {
  return !!(searchForm.value.menuName || searchForm.value.auth || searchForm.value.menuStatus)
}

function getEmptyType() {
  return hasSearchConditions() ? 'search' : 'data'
}

function getEmptyTitle() {
  return hasSearchConditions() ? '暂无搜索结果' : '暂无菜单数据'
}

function getEmptyDescription() {
  return hasSearchConditions() ? '请尝试调整搜索条件' : '请添加菜单数据'
}

function getEmptyActionText() {
  return hasSearchConditions() ? '重置搜索' : '新增菜单'
}

function handleEmptyAction() {
  if (hasSearchConditions()) {
    handleReset()
  }
  else {
    handleAdd()
  }
}

// 初始化
onMounted(() => {
  getMenuData()
  getMenuCascaderData()
})
</script>

<style scoped>
.search-form {
  margin-bottom: 0;
}

.custom-table {
  font-size: 14px;
}

.custom-table :deep(.n-data-table-thead .n-data-table-th) {
  background-color: #f8f9fa;
  font-weight: 600;
}

.custom-table :deep(.n-data-table-tbody .n-data-table-tr:hover) {
  background-color: #f5f7fa;
}

.table-wrapper {
  background-color: #fff;
}

.coi-empty__action-btn {
  min-width: 120px;
  height: 40px;
  font-size: 14px;
  font-weight: 500;
}

/* 操作按钮样式 */
.action-btn {
  width: 36px !important;
  height: 36px !important;
  min-width: 36px !important;
  min-height: 36px !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  border-radius: 50% !important;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08) !important;
  border: none !important;
  position: relative !important;
  overflow: hidden !important;
  padding: 0 !important;
}

.action-btn .n-button__content {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  width: 100% !important;
  height: 100% !important;
  padding: 0 !important;
  margin: 0 !important;
}

.action-btn .n-icon {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  margin: 0 !important;
  transform: none !important;
}

.action-btn:hover {
  transform: translateY(-2px) !important;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15) !important;
}

.action-btn:active {
  transform: translateY(0) !important;
  transition: all 0.1s !important;
}

/* 编辑按钮 */
.action-btn-edit {
  background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%) !important;
  color: white !important;
}

.action-btn-edit:hover {
  background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%) !important;
  box-shadow: 0 4px 16px rgba(59, 130, 246, 0.4) !important;
}

/* 删除按钮 */
.action-btn-delete {
  background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%) !important;
  color: white !important;
}

.action-btn-delete:hover {
  background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%) !important;
  box-shadow: 0 4px 16px rgba(239, 68, 68, 0.4) !important;
}

/* 信息按钮 */
.action-btn-info {
  background: linear-gradient(135deg, #06b6d4 0%, #0891b2 100%) !important;
  color: white !important;
}

.action-btn-info:hover {
  background: linear-gradient(135deg, #0891b2 0%, #0e7490 100%) !important;
  box-shadow: 0 4px 16px rgba(6, 182, 212, 0.4) !important;
}

/* 紧凑表单样式 */
.compact-form :deep(.n-form-item) {
  margin-bottom: 8px !important;
}

.compact-form :deep(.n-form-item .n-form-item-feedback-wrapper) {
  min-height: 0 !important;
  padding-top: 2px !important;
}

.compact-form :deep(.n-form-item .n-form-item-label) {
  padding-bottom: 2px !important;
}

.compact-form :deep(.n-input),
.compact-form :deep(.n-input-number),
.compact-form :deep(.n-cascader),
.compact-form :deep(.n-radio-group) {
  font-size: 14px !important;
}

.compact-form :deep(.n-input .n-input__input-el),
.compact-form :deep(.n-input-number .n-input__input-el) {
  padding: 8px 12px !important;
  min-height: 32px !important;
}

.compact-form :deep(.n-cascader .n-cascader-trigger) {
  min-height: 32px !important;
  padding: 8px 12px !important;
}

/* 自定义菜单选择器样式 */
.menu-selector {
  border: 1px solid #e0e0e6;
  border-radius: 6px;
  overflow: hidden;
  background: white;
}

.menu-column {
  height: 300px;
  border-right: 1px solid #e0e0e6;
}

.menu-column:last-child {
  border-right: none;
}

.column-header {
  background: #f5f5f5;
  padding: 8px 12px;
  font-size: 12px;
  font-weight: 500;
  color: #666;
  border-bottom: 1px solid #e0e0e6;
}

.menu-options {
  height: calc(100% - 32px);
  overflow-y: auto;
}

.menu-option {
  display: flex;
  align-items: center;
  padding: 8px 12px;
  cursor: pointer;
  transition: background-color 0.2s, color 0.2s;
  position: relative;
  color: #333;
}

.menu-option:hover {
  background-color: v-bind('themeColors.primaryLighter');
  color: v-bind('themeColors.primary');
}

.menu-option.active {
  color: v-bind('themeColors.primary') !important;
  font-weight: 500 !important;
}

.menu-option.active:hover {
  background-color: v-bind('themeColors.primaryLighter') !important;
  color: v-bind('themeColors.primary') !important;
}

.menu-option.active .option-text,
.menu-option.active span.option-text,
.menu-selector .menu-option.active .option-text,
.menu-selector .menu-option.active span {
  color: v-bind('themeColors.primary') !important;
  opacity: 1 !important;
  text-shadow: none !important;
  font-weight: 500 !important;
}

.menu-option.active .children-count {
  color: v-bind('themeColors.primary') !important;
  opacity: 0.7 !important;
}

/* 额外保险的选择器 */
.menu-selector .menu-column .menu-options .menu-option.active * {
  color: v-bind('themeColors.primary') !important;
}

.menu-selector .menu-column .menu-options .menu-option.active span.option-text {
  color: v-bind('themeColors.primary') !important;
  display: inline !important;
  visibility: visible !important;
  font-weight: 500 !important;
}

/* 针对Naive UI组件的覆盖 */
.menu-selector .menu-option.active .n-radio,
.menu-selector .menu-option.active .n-radio *,
.menu-selector .menu-option[data-active="true"],
.menu-selector .menu-option[data-active="true"] * {
  color: v-bind('themeColors.primary') !important;
}

.menu-option.hoverable:hover {
  background-color: v-bind('themeColors.primaryLighter');
  color: v-bind('themeColors.primary');
}

.option-text {
  flex: 1;
  margin-left: 8px;
  font-size: 14px;
}

.children-count {
  font-size: 12px;
  color: #999;
  margin-left: 4px;
}

.expand-icon {
  margin-left: 4px;
  font-size: 12px;
  color: #999;
}

.menu-option.active .expand-icon {
  color: rgba(255, 255, 255, 0.8);
}

.menu-separator {
  height: 1px;
  background-color: #e0e0e6;
  margin: 4px 0;
}

/* 滚动条样式 */
.menu-options::-webkit-scrollbar {
  width: 4px;
}

.menu-options::-webkit-scrollbar-track {
  background: transparent;
}

.menu-options::-webkit-scrollbar-thumb {
  background: #d1d5db;
  border-radius: 2px;
}

.menu-options::-webkit-scrollbar-thumb:hover {
  background: #9ca3af;
}
</style>
