<template>
  <div class="menus-page">
    <a-card class="mb-4">
      <template #title>菜单管理</template>
      <template #extra>
        <a-button v-permission="'menu:create'" type="primary" @click="handleAdd">新增菜单</a-button>
      </template>
    </a-card>

    <div class="page-content">
      <div class="left-panel">
        <a-card title="菜单目录" size="small">
          <div class="left-tree-scroll">
            <a-spin :spinning="loading">
              <a-tree v-if="dataSource.length > 0" :tree-data="dataSource"
                :field-names="{ title: 'name', key: 'id', children: 'children' }" :selected-keys="selectedKeys"
                default-expand-all show-line block-node @select="onTreeSelect">
                <template #title="{ dataRef }">
                  <span class="tree-node-title">
                    <component v-if="dataRef.icon && getIconComponent(dataRef.icon)"
                      :is="getIconComponent(dataRef.icon)!" class="tree-node-icon" />
                    <span>{{ dataRef.name }}</span>
                  </span>
                </template>
              </a-tree>
              <a-empty v-else description="暂无菜单数据" />
            </a-spin>
          </div>
        </a-card>
      </div>

      <div class="right-panel">
        <a-card title="菜单详情" size="small">
          <a-spin :spinning="detailLoading">
            <template v-if="selectedId != null">
              <a-descriptions bordered size="small" :column="2" class="mb-4">
                <a-descriptions-item label="ID">{{ detailForm.id }}</a-descriptions-item>
                <a-descriptions-item label="修改人">{{ detailForm.modifier ?? '-' }}</a-descriptions-item>
                <a-descriptions-item label="创建时间" :span="2">{{ formatTime(detailForm.createTime)
                  }}</a-descriptions-item>
                <a-descriptions-item label="编辑时间" :span="2">{{ formatTime(detailForm.modifyTime)
                  }}</a-descriptions-item>
              </a-descriptions>

              <a-form ref="detailFormRef" :model="detailForm" :rules="rules" :label-col="{ span: 6 }"
                :wrapper-col="{ span: 18 }">
                <a-form-item label="菜单名称" name="name">
                  <a-input v-model:value="detailForm.name" placeholder="请输入菜单名称" :maxlength="50" />
                </a-form-item>
                <a-form-item label="路由路径" name="path">
                  <a-input v-model:value="detailForm.path" placeholder="请输入路由路径（如：/system/users）" :maxlength="200" />
                </a-form-item>
                <a-form-item label="图标" name="icon">
                  <AntdIconPicker v-model:value="detailForm.icon" :maxlength="50" />
                </a-form-item>
                <a-form-item label="组件路径" name="component">
                  <a-input v-model:value="detailForm.component" placeholder="请输入组件路径（如：system/users/Index）"
                    :maxlength="200" />
                </a-form-item>
                <a-form-item label="权限编码" name="permission">
                  <a-input v-model:value="detailForm.permission" placeholder="请输入权限编码（如：menu:read，留空则所有用户可见）"
                    :maxlength="100" />
                </a-form-item>
                <a-form-item label="父菜单" name="parentId">
                  <a-tree-select v-model:value="detailForm.parentId" :tree-data="menuTreeOptions"
                    placeholder="请选择父菜单（不选则为顶级菜单）" :allow-clear="true" tree-default-expand-all style="width: 100%" />
                </a-form-item>
                <a-form-item label="排序" name="sort">
                  <a-input-number v-model:value="detailForm.sort" :min="0" :max="9999" placeholder="请输入排序值"
                    style="width: 100%" />
                </a-form-item>
                <a-form-item :wrapper-col="{ span: 18, offset: 6 }">
                  <a-space>
                    <a-button v-permission="'menu:update'" type="primary" :loading="saveDetailLoading"
                      @click="handleSaveDetail">
                      保存
                    </a-button>
                    <a-button v-permission.hide="'menu:delete'" danger @click="handleDeleteDetail">删除</a-button>
                  </a-space>
                </a-form-item>
              </a-form>
            </template>
            <a-empty v-else description="请从左侧选择菜单" />
          </a-spin>
        </a-card>
      </div>
    </div>

    <!-- 新增菜单弹窗 -->
    <a-modal v-model:open="modalVisible" title="新增菜单" :confirm-loading="submitLoading" @ok="handleSubmitCreate"
      @cancel="handleCancelCreate" width="600px">
      <a-form ref="createFormRef" :model="createForm" :rules="rules" :label-col="{ span: 6 }"
        :wrapper-col="{ span: 18 }">
        <a-form-item label="菜单名称" name="name">
          <a-input v-model:value="createForm.name" placeholder="请输入菜单名称" :maxlength="50" />
        </a-form-item>
        <a-form-item label="路由路径" name="path">
          <a-input v-model:value="createForm.path" placeholder="请输入路由路径（如：/system/users）" :maxlength="200" />
        </a-form-item>
        <a-form-item label="图标" name="icon">
          <AntdIconPicker v-model:value="createForm.icon" :maxlength="50" />
        </a-form-item>
        <a-form-item label="组件路径" name="component">
          <a-input v-model:value="createForm.component" placeholder="请输入组件路径（如：system/users/Index）" :maxlength="200" />
        </a-form-item>
        <a-form-item label="权限编码" name="permission">
          <a-input v-model:value="createForm.permission" placeholder="请输入权限编码（如：menu:read，留空则所有用户可见）"
            :maxlength="100" />
        </a-form-item>
        <a-form-item label="父菜单" name="parentId">
          <a-tree-select v-model:value="createForm.parentId" :tree-data="menuTreeOptionsForCreate"
            placeholder="请选择父菜单（不选则为顶级菜单）" :allow-clear="true" tree-default-expand-all style="width: 100%" />
        </a-form-item>
        <a-form-item label="排序" name="sort">
          <a-input-number v-model:value="createForm.sort" :min="0" :max="9999" placeholder="请输入排序值"
            style="width: 100%" />
        </a-form-item>
      </a-form>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, nextTick, computed, h } from 'vue'
import { message, Modal } from 'ant-design-vue'
import type { FormInstance } from 'ant-design-vue'
import * as Icons from '@ant-design/icons-vue'
import AntdIconPicker from '@/components/AntdIconPicker.vue'
import { menusApi, type Menu, type CreateMenuForm, type UpdateMenuForm } from '@/api/menus'
import { useSimpleListRequest } from '@/composables/useSimpleListRequest'
import { useAuthStore } from '@/stores/auth'

const getIconComponent = (iconName: string | null | undefined) => {
  if (!iconName) return null
  const IconComponent = (Icons as Record<string, unknown>)[iconName]
  if (IconComponent) {
    return () => h(IconComponent as Parameters<typeof h>[0])
  }
  return null
}

const formatTime = (text: string | undefined) =>
  text ? new Date(text).toISOString().replace('T', ' ').substring(0, 19) : '-'

const authStore = useAuthStore()

const submitLoading = ref(false)
const saveDetailLoading = ref(false)
const detailLoading = ref(false)
const modalVisible = ref(false)
const createFormRef = ref<FormInstance>()
const detailFormRef = ref<FormInstance>()

const selectedKeys = ref<(string | number)[]>([])
const selectedId = ref<number | null>(null)

const {
  loading,
  dataSource,
  refresh: refreshList,
} = useSimpleListRequest<Menu>({
  requestFn: menusApi.getList,
  errorMessage: '获取菜单列表失败',
})

const createForm = reactive<CreateMenuForm>({
  name: '',
  path: '',
  icon: '',
  component: '',
  parentId: undefined,
  permission: '',
  sort: 0,
})

const detailForm = reactive({
  id: 0,
  name: '',
  path: '',
  icon: '',
  component: '',
  parentId: undefined as number | undefined,
  permission: '',
  sort: 0,
  createTime: '' as string | undefined,
  modifyTime: '' as string | undefined,
  modifier: undefined as number | undefined,
})

const rules = {
  name: [
    { required: true, message: '请输入菜单名称', trigger: 'blur' },
    { max: 50, message: '菜单名称不能超过50个字符', trigger: 'blur' },
  ],
  path: [{ max: 200, message: '路由路径不能超过200个字符', trigger: 'blur' }],
  icon: [{ max: 50, message: '图标名称不能超过50个字符', trigger: 'blur' }],
  component: [{ max: 200, message: '组件路径不能超过200个字符', trigger: 'blur' }],
  permission: [{ max: 100, message: '权限编码不能超过100个字符', trigger: 'blur' }],
  sort: [
    { type: 'number', min: 0, max: 9999, message: '排序值必须在0-9999之间', trigger: 'blur' },
  ],
}

// 右侧编辑：父菜单树（排除当前节点）
const menuTreeOptions = computed(() => {
  const buildOptions = (menus: Menu[], excludeId?: number): { title: string; value: number; key: number; children?: ReturnType<typeof buildOptions> }[] => {
    return menus
      .filter((menu) => menu.id !== excludeId)
      .map((menu) => ({
        title: menu.name,
        value: menu.id,
        key: menu.id,
        children: menu.children?.length ? buildOptions(menu.children, excludeId) : undefined,
      }))
  }
  return buildOptions(dataSource.value, selectedId.value ?? undefined)
})

// 新增弹窗：不排除节点（无编辑中的 id）
const menuTreeOptionsForCreate = computed(() => {
  const buildOptions = (menus: Menu[]): { title: string; value: number; key: number; children?: ReturnType<typeof buildOptions> }[] => {
    return menus.map((menu) => ({
      title: menu.name,
      value: menu.id,
      key: menu.id,
      children: menu.children?.length ? buildOptions(menu.children) : undefined,
    }))
  }
  return buildOptions(dataSource.value)
})

const resetCreateForm = () => {
  createForm.name = ''
  createForm.path = ''
  createForm.icon = ''
  createForm.component = ''
  createForm.parentId = undefined
  createForm.permission = ''
  createForm.sort = 0
}

const loadDetail = async (id: number) => {
  selectedId.value = id
  selectedKeys.value = [id]
  detailLoading.value = true
  try {
    const detail = await menusApi.getDetail(id)
    detailForm.id = detail.id
    detailForm.name = detail.name
    detailForm.path = detail.path || ''
    detailForm.icon = detail.icon || ''
    detailForm.component = detail.component || ''
    detailForm.parentId = detail.parentId || undefined
    detailForm.permission = detail.permission || ''
    detailForm.sort = detail.sort ?? 0
    detailForm.createTime = detail.createTime
    detailForm.modifyTime = detail.modifyTime
    detailForm.modifier = detail.modifier
  } catch {
    message.error('获取菜单详情失败')
    selectedKeys.value = []
    selectedId.value = null
  } finally {
    detailLoading.value = false
  }
}

const onTreeSelect = (keys: (string | number)[]) => {
  if (!keys.length) {
    selectedKeys.value = []
    selectedId.value = null
    return
  }
  const id = Number(keys[0])
  loadDetail(id)
}

const handleAdd = () => {
  if (!authStore.hasPermission('menu:create')) {
    message.error('您没有创建菜单的权限')
    return
  }
  modalVisible.value = true
  nextTick(() => {
    createFormRef.value?.resetFields()
    resetCreateForm()
    if (selectedId.value != null) {
      createForm.parentId = selectedId.value
    }
  })
}

const handleSubmitCreate = async () => {
  try {
    await createFormRef.value?.validate()
    submitLoading.value = true
    const createData: CreateMenuForm = {
      name: createForm.name,
      path: createForm.path || undefined,
      icon: createForm.icon || undefined,
      component: createForm.component || undefined,
      parentId: createForm.parentId || undefined,
      permission: createForm.permission || undefined,
      sort: createForm.sort ?? 0,
    }
    const created = await menusApi.create(createData)
    message.success('新增成功')
    modalVisible.value = false
    await refreshList()
    if (created?.id) {
      await loadDetail(created.id)
    }
  } catch (error: unknown) {
    const err = error as { errorFields?: unknown; response?: { data?: { message?: string } } }
    if (err?.errorFields) return
    message.error(err?.response?.data?.message || '新增失败')
  } finally {
    submitLoading.value = false
  }
}

const handleCancelCreate = () => {
  modalVisible.value = false
  createFormRef.value?.resetFields()
}

const handleSaveDetail = async () => {
  if (selectedId.value == null) return
  try {
    await detailFormRef.value?.validate()
    saveDetailLoading.value = true
    const updateData: UpdateMenuForm = {
      name: detailForm.name,
      path: detailForm.path || undefined,
      icon: detailForm.icon || undefined,
      component: detailForm.component || undefined,
      parentId: detailForm.parentId || undefined,
      permission: detailForm.permission || undefined,
      sort: detailForm.sort ?? 0,
    }
    await menusApi.update(selectedId.value, updateData)
    message.success('保存成功')
    await refreshList()
    await loadDetail(selectedId.value)
  } catch (error: unknown) {
    const err = error as { errorFields?: unknown; response?: { data?: { message?: string } } }
    if (err?.errorFields) return
    message.error(err?.response?.data?.message || '保存失败')
  } finally {
    saveDetailLoading.value = false
  }
}

const handleDeleteDetail = () => {
  if (selectedId.value == null) return
  Modal.confirm({
    title: '确认删除',
    content: `确定要删除菜单 "${detailForm.name}" 吗？删除后其子菜单也会被删除，且无法恢复。`,
    okText: '确定',
    okType: 'danger',
    cancelText: '取消',
    onOk: async () => {
      try {
        const id = selectedId.value!
        await menusApi.delete(id)
        message.success('删除成功')
        selectedKeys.value = []
        selectedId.value = null
        await refreshList()
      } catch (error: unknown) {
        const err = error as { response?: { data?: { message?: string } } }
        message.error(err?.response?.data?.message || '删除失败')
      }
    },
  })
}
</script>
<style>
.menus-page .ant-tree-switcher.ant-tree-switcher-noop {
  display: none;
}
</style>
<style scoped>
.page-content {
  display: flex;
  gap: 16px;
}

.left-panel {
  width: 280px;
  flex-shrink: 0;
  min-height: 0;
}

/* 左侧菜单树独立纵向滚动，避免整页被撑高 */
.left-tree-scroll {
  max-height: calc(100vh - 240px);
  overflow-x: hidden;
  overflow-y: auto;
}

.right-panel {
  flex: 1;
  min-width: 0;
}

.tree-node-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.tree-node-icon {
  font-size: 14px;
}
</style>
