<template>
  <n-layout :has-sider="layoutConfig.siderPosition !== 'top'" class="layout" :class="layoutConfig.siderPosition === 'top' ? 'layout-top' : ''">
    <!-- 侧边栏（左侧/右侧模式） -->
    <n-layout-sider
      v-if="layoutConfig.siderPosition !== 'top'"
      bordered
      collapse-mode="width"
      :collapsed-width="64"
      :width="240"
      :collapsed="collapsed"
      show-trigger
      :position="layoutConfig.siderPosition === 'right' ? 'right' : 'left'"
      @collapse="collapsed = true"
      @expand="collapsed = false"
      class="layout-sider"
      :class="[`theme-${layoutConfig.theme}`, layoutConfig.siderPosition === 'right' ? 'sider-right' : '']"
    >
      <!-- Logo -->
      <div class="logo" :class="{ 'logo-collapsed': collapsed, 'logo-primary': themeStore.headerUsePrimaryColor }" :style="themeStore.headerUsePrimaryColor ? { background: themeStore.primaryColor, borderBottomColor: themeStore.primaryColor } : {}">
        <SiteLogoMark
          img-class="logo-img"
          icon-class="logo-icon"
          :icon-style="logoIconStyle"
        />
        <transition name="fade">
          <span v-if="!collapsed" class="logo-text">{{ siteName }}</span>
          <!-- <span v-if="!collapsed" class="logo-text">伊特智造MES</span> -->
        </transition>
      </div>

      <!-- 菜单 -->
      <n-menu
        :collapsed="collapsed"
        :collapsed-width="64"
        :collapsed-icon-size="22"
        :options="menuOptions"
        :value="activeMenu"
        @update:value="handleMenuClick"
        class="layout-menu"
      />
    </n-layout-sider>

    <!-- 主内容区 -->
    <n-layout>
      <!-- 顶部导航 -->
      <n-layout-header bordered class="layout-header" :class="[`theme-${layoutConfig.theme}`, { 'header-primary': themeStore.headerUsePrimaryColor }]" :style="headerStyle">
        <!-- 顶部菜单模式下的Logo -->
        <div v-if="layoutConfig.siderPosition === 'top'" class="header-logo">
          <SiteLogoMark
            img-class="logo-img"
            icon-class="logo-icon"
            :icon-style="logoIconStyle"
          />
          <span class="logo-text">{{ siteName }}</span>
        </div>

        <!-- 顶部菜单模式下的菜单 -->
        <div v-if="layoutConfig.siderPosition === 'top'" class="header-menu">
          <n-menu
            mode="horizontal"
            :options="menuOptions"
            :value="activeMenu"
            @update:value="handleMenuClick"
          />
        </div>

        <div v-else class="header-left">
          <n-breadcrumb>
            <n-breadcrumb-item v-for="item in breadcrumbs" :key="item.path">
              {{ item.title }}
            </n-breadcrumb-item>
          </n-breadcrumb>
        </div>

        <div class="header-right">
          <!-- 菜单搜索 -->
          <n-popover trigger="click" placement="bottom" :width="400" v-model:show="searchVisible">
            <template #trigger>
              <div class="header-icon" title="搜索菜单">
                <n-icon size="20"><SearchOutline /></n-icon>
              </div>
            </template>
            <div class="search-panel">
              <n-input
                v-model:value="searchKeyword"
                placeholder="搜索菜单..."
                clearable
                autofocus
                @input="handleSearch"
              >
                <template #prefix>
                  <n-icon><SearchOutline /></n-icon>
                </template>
              </n-input>
              <div class="search-results" v-if="searchResults.length > 0">
                <div
                  v-for="item in searchResults"
                  :key="item.key"
                  class="search-result-item"
                  @click="goToMenu(item)"
                >
                  <n-icon size="16" class="result-icon">
                    <component :is="iconMap[item.iconName] || MenuOutline" />
                  </n-icon>
                  <span class="result-label">{{ item.label }}</span>
                  <span class="result-path">{{ item.path }}</span>
                </div>
              </div>
              <n-empty v-else-if="searchKeyword" description="未找到匹配菜单" size="small" style="padding: 20px 0" />
            </div>
          </n-popover>

          <!-- 全屏 -->
          <div class="header-icon" @click="toggleFullscreen" :title="isFullscreen ? '退出全屏' : '全屏'">
            <n-icon size="20">
              <ContractOutline v-if="isFullscreen" />
              <ExpandOutline v-else />
            </n-icon>
          </div>

          <!-- 换肤设置 -->
          <n-popover trigger="click" placement="bottom-end" :width="300">
            <template #trigger>
              <div class="header-icon" title="主题设置">
                <n-icon size="20"><ColorPaletteOutline /></n-icon>
              </div>
            </template>
            <div class="theme-panel">
              <div class="theme-section">
                <div class="theme-title">菜单位置</div>
                <div class="layout-options">
                  <div
                    class="layout-option"
                    :class="{ active: layoutConfig.siderPosition === 'left' }"
                    @click="setLayoutPosition('left')"
                  >
                    <div class="layout-preview layout-left">
                      <div class="preview-sider"></div>
                      <div class="preview-main"></div>
                    </div>
                    <span>左侧菜单</span>
                  </div>
                  <div
                    class="layout-option"
                    :class="{ active: layoutConfig.siderPosition === 'right' }"
                    @click="setLayoutPosition('right')"
                  >
                    <div class="layout-preview layout-right">
                      <div class="preview-main"></div>
                      <div class="preview-sider"></div>
                    </div>
                    <span>右侧菜单</span>
                  </div>
                  <div
                    class="layout-option"
                    :class="{ active: layoutConfig.siderPosition === 'top' }"
                    @click="setLayoutPosition('top')"
                  >
                    <div class="layout-preview layout-top">
                      <div class="preview-header"></div>
                      <div class="preview-content"></div>
                    </div>
                    <span>顶部菜单</span>
                  </div>
                </div>
              </div>
              <div class="theme-section">
                <div class="theme-title">主题风格</div>
                <div class="theme-modes">
                  <div
                    v-for="theme in themeOptions"
                    :key="theme.value"
                    class="theme-mode"
                    :class="{ active: layoutConfig.theme === theme.value }"
                    @click="setTheme(theme.value)"
                  >
                    <div class="theme-mode-preview" :style="{ background: theme.color }">
                      <n-icon v-if="layoutConfig.theme === theme.value" :color="theme.value === 'light' ? '#18a058' : '#fff'"><CheckmarkOutline /></n-icon>
                    </div>
                    <span>{{ theme.label }}</span>
                  </div>
                </div>
              </div>
              <div class="theme-section">
                <div class="theme-title">主题色</div>
                <div class="color-options">
                  <div
                    v-for="item in themeColors"
                    :key="item.color"
                    class="color-option"
                    :class="{ active: themeStore.primaryColor === item.color }"
                    :style="{ backgroundColor: item.color }"
                    :title="item.name"
                    @click="themeStore.setPrimaryColor(item.color)"
                  >
                    <n-icon v-if="themeStore.primaryColor === item.color" color="#fff"><CheckmarkOutline /></n-icon>
                  </div>
                </div>
              </div>
              <div class="theme-section">
                <div class="theme-switch-row">
                  <span class="theme-title" style="margin-bottom: 0">顶栏应用主题色</span>
                  <n-switch :value="themeStore.headerUsePrimaryColor" @update:value="themeStore.setHeaderUsePrimaryColor" size="small" />
                </div>
              </div>
              <div class="theme-section">
                <div class="theme-switch-row">
                  <span class="theme-title" style="margin-bottom: 0">显示页签</span>
                  <n-switch :value="themeStore.showTabs" @update:value="themeStore.setShowTabs" size="small" />
                </div>
              </div>
            </div>
          </n-popover>

          <!-- 消息通知 -->
          <n-popover trigger="click" placement="bottom-end" :width="360" @update:show="handleMessagePopoverShow">
            <template #trigger>
              <n-badge :value="messageStore.totalUnread()" :max="99" :show-zero="false">
                <div class="header-icon" title="消息通知">
                  <n-icon size="20"><NotificationsOutline /></n-icon>
                </div>
              </n-badge>
            </template>
            <div class="message-popover">
              <div class="message-tabs">
                <n-tabs v-model:value="messageTab" type="line" size="small" @update:value="handleTabChange" class="message-tabs-inner">
                  <n-tab-pane name="notice" tab="通知">
                    <template #tab>
                      <n-badge :value="messageStore.noticeCount" :max="99" :show-zero="false" :offset="[8, -2]">
                        <span class="tab-text">通知</span>
                      </n-badge>
                    </template>
                  </n-tab-pane>
                  <n-tab-pane name="chat" tab="消息">
                    <template #tab>
                      <n-badge :value="messageStore.chatCount" :max="99" :show-zero="false" :offset="[8, -2]">
                        <span class="tab-text">消息</span>
                      </n-badge>
                    </template>
                  </n-tab-pane>
                </n-tabs>
              </div>
              <div class="message-list" ref="messageListRef" @scroll="handleMessageScroll">
                <n-spin :show="messageLoading && messagePage === 1">
                  <!-- 通知列表 -->
                  <template v-if="messageTab === 'notice'">
                    <div v-for="item in recentNotices" :key="item.id" class="message-item" @click="handleNoticeClick(item)">
                      <div class="message-item-header">
                        <n-tag :type="item.noticeType === 1 ? 'info' : item.noticeType === 2 ? 'warning' : 'error' " size="small">
                          {{ item.noticeType === 1 ? '通知' : item.noticeType === 2 ? '公告' : '异常通知' }}
                        </n-tag>
                        <span class="message-time">{{ formatMessageTime(item.createTime) }}</span>
                      </div>
                      <div class="message-title">{{ item.title }}</div>
                      <div class="message-content">{{ stripHtml(item.content) }}</div>
                    </div>
                    <n-empty v-if="recentNotices.length === 0 && !messageLoading" description="暂无通知" size="small" style="padding: 30px 0" />
                  </template>
                  <!-- 聊天消息列表 -->
                  <template v-else>
                    <div v-for="item in recentChats" :key="item.senderId || item.id" class="message-item" @click="handleChatClick(item)">
                      <div class="message-item-row">
                        <n-avatar round size="small" :src="item.senderAvatar">
                          {{ item.senderName?.charAt(0) || 'U' }}
                        </n-avatar>
                        <div class="message-item-content">
                          <div class="message-item-header">
                            <span class="message-sender">{{ item.senderName || '用户' }}</span>
                            <span class="message-time">{{ formatMessageTime(item.sendTime) }}</span>
                          </div>
                          <div class="message-content">{{ item.content }}</div>
                        </div>
                      </div>
                    </div>
                    <n-empty v-if="recentChats.length === 0 && !messageLoading" description="暂无消息" size="small" style="padding: 30px 0" />
                  </template>
                </n-spin>
                <!-- 加载更多 -->
                <div v-if="messageLoading && messagePage > 1" class="message-loading">
                  <n-spin size="small" />
                </div>
                <div v-if="!hasMoreMessages && (recentNotices.length > 0 || recentChats.length > 0)" class="message-no-more">
                  没有更多了
                </div>
              </div>
              <div class="message-footer">
                <n-button v-if="messageStore.noticeCount > 0 && messageTab === 'notice'" text size="small" @click="handleMarkAllRead">
                  全部已读
                </n-button>
                <n-button text type="primary" @click="goToMessage">查看全部</n-button>
              </div>
            </div>
          </n-popover>

          <n-dropdown :options="userOptions" @select="handleUserAction">
            <div class="user-info">
              <n-avatar
                round
                size="small"
                :src="userStore.avatar || undefined"
              >
                {{ userStore.nickname?.charAt(0) || 'U' }}
              </n-avatar>
              <span class="user-name">{{ userStore.nickname }}</span>
              <n-icon size="16">
                <ChevronDownOutline />
              </n-icon>
            </div>
          </n-dropdown>
        </div>
      </n-layout-header>

      <!-- 页签栏 -->
      <TabBar v-if="themeStore.showTabs" />

      <!-- 内容区 -->
      <n-layout-content class="layout-content">
        <router-view v-slot="{ Component }">
          <transition name="fade" mode="out-in">
            <component :is="Component" />
          </transition>
        </router-view>
      </n-layout-content>
    </n-layout>

    <!-- 个人信息弹窗 -->
    <ProfileModal v-model:show="showProfileModal" />

    <!-- 修改密码弹窗 -->
    <PasswordModal v-model:show="showPasswordModal" />

    <!-- 消息通知弹窗 -->
    <MessageNotification />
  </n-layout>
</template>

<script setup lang="ts">
import { ref, computed, h, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { NIcon, useMessage, useDialog, type MenuOption } from 'naive-ui'
import {
  HomeOutline,
  SettingsOutline,
  PersonOutline,
  PeopleOutline,
  MenuOutline,
  LogOutOutline,
  KeyOutline,
  ChevronDownOutline,
  BookOutline,
  BusinessOutline,
  GitNetworkOutline,
  IdCardOutline,
  DocumentTextOutline,
  ListOutline,
  LogInOutline,
  PulseOutline,
  PeopleCircleOutline,
  TimerOutline,
  ServerOutline,
  DesktopOutline,
  SettingsSharp,
  FolderOpenOutline,
  DocumentOutline,
  CloudOutline,
  NotificationsOutline,
  ChatbubbleOutline,
  SearchOutline,
  ExpandOutline,
  ContractOutline,
  ColorPaletteOutline,
  CheckmarkOutline
} from '@vicons/ionicons5'
import { useUserStore } from '@/stores/user'
import { useMessageStore } from '@/stores/message'
import { useSiteStore } from '@/stores/site'
import { useThemeStore, themeColors } from '@/stores/theme'
import ProfileModal from '@/components/ProfileModal.vue'
import PasswordModal from '@/components/PasswordModal.vue'
import MessageNotification from '@/components/MessageNotification.vue'
import TabBar from '@/components/TabBar.vue'
import SiteLogoMark from '@/components/SiteLogoMark.vue'
import { noticeApi, chatApi, type SysNotice, type ChatMessage } from '@/api/message'
import { iconMap as externalIconMap } from '@/utils/icons'

const route = useRoute()
const router = useRouter()
const message = useMessage()
const dialog = useDialog()
const userStore = useUserStore()
const messageStore = useMessageStore()
const siteStore = useSiteStore()
const themeStore = useThemeStore()

// 站点配置
const siteName = computed(() => siteStore.siteName || 'CSY Admin')
const logoIconStyle = computed(() => ({
  background: themeStore.headerUsePrimaryColor ? '#fff' : themeStore.primaryColor,
  color: themeStore.headerUsePrimaryColor ? themeStore.primaryColor : '#fff',
}))

// 注册全局message
window.$message = message

const collapsed = ref(false)
const showProfileModal = ref(false)
const showPasswordModal = ref(false)
const messageTab = ref('notice')

// 消息相关
const messageLoading = ref(false)
const recentNotices = ref<SysNotice[]>([])
const recentChats = ref<ChatMessage[]>([])
const messagePage = ref(1)
const hasMoreMessages = ref(true)
const messageListRef = ref<HTMLElement | null>(null)

// 搜索相关
const searchVisible = ref(false)
const searchKeyword = ref('')
const searchResults = ref<Array<{ key: string; label: string; path: string; iconName: string }>>([])

// 全屏相关
const isFullscreen = ref(false)

// 布局配置 - 使用 theme store
const layoutConfig = computed(() => ({
  siderPosition: themeStore.siderPosition,
  theme: themeStore.mode
}))

// 主题选项（仅黑白两种）
const themeOptions = [
  { value: 'dark' as const, color: '#001529', label: '暗色主题' },
  { value: 'light' as const, color: '#ffffff', label: '亮色主题' }
]

// 顶栏动态样式
const headerStyle = computed(() => {
  if (themeStore.headerUsePrimaryColor) {
    return {
      background: themeStore.primaryColor,
      borderBottomColor: themeStore.primaryColor
    }
  }
  return {}
})

// 初始化WebSocket和加载未读数
onMounted(() => {
  messageStore.initWebSocket()
  loadUnreadCount()
  // 监听全屏变化
  document.addEventListener('fullscreenchange', handleFullscreenChange)
})

// 加载未读数量
async function loadUnreadCount() {
  try {
    const [noticeCount, chatCount] = await Promise.all([
      noticeApi.getUnreadCount(),
      chatApi.getUnreadCount()
    ])
    messageStore.setUnreadCount(noticeCount, chatCount)
  } catch (error) {
    // 忽略错误
  }
}

// 跳转到消息页面
function goToMessage() {
  if (messageTab.value === 'notice') {
    router.push('/message/notice')
  } else {
    router.push('/message/chat')
  }
}

// 消息弹窗显示时加载数据
async function handleMessagePopoverShow(show: boolean) {
  if (show) {
    loadUnreadCount()
    // 重置分页
    messagePage.value = 1
    hasMoreMessages.value = true
    if (messageTab.value === 'notice') {
      recentNotices.value = []
      await loadRecentNotices()
    } else {
      recentChats.value = []
      await loadRecentChats()
    }
  }
}

// Tab 切换时加载数据
async function handleTabChange(tab: string) {
  // 重置分页
  messagePage.value = 1
  hasMoreMessages.value = true
  if (tab === 'notice') {
    recentNotices.value = []
    await loadRecentNotices()
  } else {
    recentChats.value = []
    await loadRecentChats()
  }
}

// 加载最近通知
async function loadRecentNotices(append = false) {
  if (messageLoading.value) return
  try {
    messageLoading.value = true
    const res = await noticeApi.myNotices({ page: messagePage.value, pageSize: 10 })
    const list = res.list || []
    if (append) {
      recentNotices.value = [...recentNotices.value, ...list]
    } else {
      recentNotices.value = list
    }
    hasMoreMessages.value = list.length >= 10
  } catch (error) {
    // 忽略错误
  } finally {
    messageLoading.value = false
  }
}

// 加载最近聊天
async function loadRecentChats(append = false) {
  if (messageLoading.value) return
  try {
    messageLoading.value = true
    const res = await chatApi.getContacts()
    const list = res || []
    if (append) {
      recentChats.value = [...recentChats.value, ...list]
    } else {
      recentChats.value = list
    }
    // 聊天联系人一次性加载，不分页
    hasMoreMessages.value = false
  } catch (error) {
    // 忽略错误
  } finally {
    messageLoading.value = false
  }
}

// 滚动加载更多
function handleMessageScroll(e: Event) {
  const target = e.target as HTMLElement
  const { scrollTop, scrollHeight, clientHeight } = target
  
  // 距离底部 50px 时加载更多
  if (scrollHeight - scrollTop - clientHeight < 50 && hasMoreMessages.value && !messageLoading.value) {
    messagePage.value++
    if (messageTab.value === 'notice') {
      loadRecentNotices(true)
    }
    // 聊天不做分页
  }
}

// 标记全部已读
async function handleMarkAllRead() {
  try {
    await noticeApi.markAllAsRead()
    messageStore.clearNoticeCount()
    // 刷新列表
    messagePage.value = 1
    await loadRecentNotices()
    message.success('已全部标记为已读')
  } catch (error) {
    // 忽略
  }
}

// 格式化消息时间
function formatMessageTime(time: string | undefined): string {
  if (!time) return ''
  const date = new Date(time)
  const now = new Date()
  const diff = now.getTime() - date.getTime()
  
  if (diff < 60000) return '刚刚'
  if (diff < 3600000) return Math.floor(diff / 60000) + '分钟前'
  if (diff < 86400000) return Math.floor(diff / 3600000) + '小时前'
  if (diff < 604800000) return Math.floor(diff / 86400000) + '天前'
  
  return `${date.getMonth() + 1}/${date.getDate()}`
}

// 去除 HTML 标签
function stripHtml(html: string | undefined): string {
  if (!html) return ''
  return html.replace(/<[^>]*>/g, '').substring(0, 50)
}

// 点击通知
async function handleNoticeClick(item: SysNotice) {
  // 标记已读
  if (item.id) {
    try {
      await noticeApi.markAsRead(item.id)
      // 刷新未读数量
      loadUnreadCount()
    } catch (error) {
      // 忽略
    }
  }
  router.push({ path: '/message/notice', query: { id: item.id?.toString() } })
}

// 点击聊天
async function handleChatClick(item: ChatMessage) {
  // 标记已读
  if (item.senderId) {
    try {
      await chatApi.markAsRead(item.senderId)
      // 刷新未读数量
      loadUnreadCount()
    } catch (error) {
      // 忽略
    }
  }
  router.push({ path: '/message/chat', query: { userId: item.senderId?.toString() } })
}

// 搜索菜单
function handleSearch() {
  if (!searchKeyword.value.trim()) {
    searchResults.value = []
    return
  }

  const keyword = searchKeyword.value.toLowerCase()
  const results: Array<{ key: string; label: string; path: string; iconName: string }> = []

  // 遍历菜单获取所有可搜索项
  function searchMenu(options: any[], parentPath: string = '') {
    for (const item of options) {
      const label = item.label as string
      if (label.toLowerCase().includes(keyword)) {
        if (!item.children) {
          results.push({
            key: item.key,
            label: label,
            path: parentPath ? `${parentPath} / ${label}` : label,
            iconName: getIconName(item.key)
          })
        }
      }
      if (item.children) {
        searchMenu(item.children, parentPath ? `${parentPath} / ${label}` : label)
      }
    }
  }

  searchMenu(menuOptions.value)
  searchResults.value = results.slice(0, 10)
}

// 获取图标名称
function getIconName(key: string): string {
  const iconMapping: Record<string, string> = {
    '/dashboard': 'HomeOutline',
    '/system/user': 'PersonOutline',
    '/system/role': 'PeopleOutline',
    '/system/menu': 'MenuOutline',
    '/system/dict': 'BookOutline',
    '/system/config': 'SettingsSharp',
    '/org/dept': 'GitNetworkOutline',
    '/org/post': 'IdCardOutline',
    '/log/operlog': 'ListOutline',
    '/log/loginlog': 'LogInOutline',
    '/system/file': 'DocumentOutline',
    '/message/notice': 'NotificationsOutline',
    '/message/chat': 'ChatbubbleOutline',
    '/monitor/online': 'PeopleCircleOutline',
    '/monitor/job': 'TimerOutline',
    '/monitor/cache': 'ServerOutline',
    '/monitor/server': 'DesktopOutline'
  }
  return iconMapping[key] || 'MenuOutline'
}

// 跳转到菜单
function goToMenu(item: { key: string }) {
  router.push(item.key)
  searchVisible.value = false
  searchKeyword.value = ''
  searchResults.value = []
}

// 切换全屏
function toggleFullscreen() {
  if (!document.fullscreenElement) {
    document.documentElement.requestFullscreen()
  } else {
    document.exitFullscreen()
  }
}

// 监听全屏变化
function handleFullscreenChange() {
  isFullscreen.value = !!document.fullscreenElement
}

// 设置布局位置
function setLayoutPosition(position: 'left' | 'right' | 'top') {
  themeStore.setSiderPosition(position)
}

// 设置主题
function setTheme(theme: 'dark' | 'light') {
  themeStore.setMode(theme)
}

// 图标映射
const iconMap: Record<string, any> = {
  HomeOutline,
  SettingsOutline,
  PersonOutline,
  PeopleOutline,
  MenuOutline,
  BookOutline,
  BusinessOutline,
  GitNetworkOutline,
  IdCardOutline,
  DocumentTextOutline,
  ListOutline,
  LogInOutline,
  PulseOutline,
  PeopleCircleOutline,
  TimerOutline,
  ServerOutline,
  DesktopOutline,
  SettingsSharp,
  FolderOpenOutline,
  DocumentOutline,
  CloudOutline,
  NotificationsOutline,
  ChatbubbleOutline
}

// 合并外部图标映射（已在顶部导入）
Object.assign(iconMap, externalIconMap)

// 渲染图标
function renderIcon(iconName?: string) {
  if (!iconName) return undefined
  const icon = iconMap[iconName]
  if (!icon) return undefined
  return () => h(NIcon, null, { default: () => h(icon) })
}

// 将后台菜单数据转换为 Naive UI 菜单格式
function convertMenus(menus: typeof userStore.menus): MenuOption[] {
  if (!menus || !Array.isArray(menus)) {
    return []
  }
  return menus
    .filter(menu => menu.visible === 1 && menu.type !== 3) // 过滤隐藏菜单和按钮
    .sort((a, b) => a.sort - b.sort) // 按排序字段排序
    .map(menu => {
      // 确保菜单路径是绝对路径（以 / 开头）
      let menuPath = menu.path || `/menu-${menu.id}`
      if (menuPath && !menuPath.startsWith('/') && menu.type === 2) {
        menuPath = '/' + menuPath
      }
      
      // 外链菜单（目录或菜单类型）使用特殊的 key 格式：external:url
      const isExternal = menu.isFrame === 1 && menu.component
      const menuKey = isExternal ? `external:${menu.component}` : menuPath
      
      const option: MenuOption = {
        label: menu.name,
        key: menuKey,
        icon: renderIcon(menu.icon)
      }
      
      // 非外链菜单才处理子菜单
      if (!isExternal && menu.children && menu.children.length > 0) {
        const children = convertMenus(menu.children)
        if (children.length > 0) {
          option.children = children
        }
      }
      return option
    })
}

// 菜单配置 - 从后台动态获取
const menuOptions = computed<MenuOption[]>(() => {
  // 添加首页菜单
  const homeMenu: MenuOption = {
    label: '首页',
    key: '/dashboard',
    icon: renderIcon('HomeOutline')
  }
  
  // 从 userStore 获取动态菜单
  const dynamicMenus = convertMenus(userStore.menus)
  
  return [homeMenu, ...dynamicMenus]
})

// 当前激活菜单
const activeMenu = computed(() => route.path)

// 面包屑
const breadcrumbs = computed(() => {
  const items: Array<{ path: string; title: string }> = []
  if (route.path === '/dashboard') {
    items.push({ path: '/dashboard', title: '首页' })
  } else if (route.path.startsWith('/system')) {
    items.push({ path: '/system', title: '系统管理' })
    if (route.path === '/system/user') {
      items.push({ path: '/system/user', title: '用户管理' })
    } else if (route.path === '/system/role') {
      items.push({ path: '/system/role', title: '角色管理' })
    } else if (route.path === '/system/menu') {
      items.push({ path: '/system/menu', title: '菜单管理' })
    }
  }
  return items
})

// 用户下拉选项
const userOptions = [
  {
    label: '个人中心',
    key: 'profile',
    icon: () => h(NIcon, null, { default: () => h(PersonOutline) })
  },
  {
    label: '修改密码',
    key: 'password',
    icon: () => h(NIcon, null, { default: () => h(KeyOutline) })
  },
  {
    type: 'divider',
    key: 'd1'
  },
  {
    label: '退出登录',
    key: 'logout',
    icon: () => h(NIcon, null, { default: () => h(LogOutOutline) })
  }
]

// 菜单点击
function handleMenuClick(key: string) {
  // 判断是否是外链目录
  if (key.startsWith('external:')) {
    const url = key.replace('external:', '')
    window.open(url, '_blank')
    return
  }
  router.push(key)
}

// 用户操作
function handleUserAction(key: string) {
  if (key === 'logout') {
    dialog.warning({
      title: '提示',
      content: '确定要退出登录吗？',
      positiveText: '确定',
      negativeText: '取消',
      onPositiveClick: () => {
        userStore.logout().then(() => {
          userStore.setinit(true)
        })
        message.success('已退出登录')
      }
    })
  } else if (key === 'profile') {
    router.push('/profile')
  } else if (key === 'password') {
    showPasswordModal.value = true
  }
}
</script>

<style lang="scss" scoped>
.layout {
  height: 100vh;
}

.layout-sider {
  background: #FFFFFF;
  transition: background-color 0.3s;

  :deep(.n-layout-sider-scroll-container) {
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
}

body.dark-theme .layout-sider {
  background: #18181c;
}

.logo {
  height: 60px;
  display: flex;
  align-items: center;
  padding: 0 20px;
  gap: 12px;
  border-bottom: 1px solid #E5E7EB;
  transition: all 0.3s;

  &.logo-collapsed {
    padding: 0 16px;
    justify-content: center;
  }
}

body.dark-theme .logo {
  border-bottom-color: #3f3f46;
}

// 侧边栏logo区域应用主题色时的样式
.logo.logo-primary {
  .logo-text {
    color: #fff;
  }

  .logo-icon {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  }
}

.logo-img {
  width: 32px;
  height: 32px;
  object-fit: contain;
  border-radius: 8px;
  flex-shrink: 0;
}

.logo-icon {
  width: 32px;
  height: 32px;
  background: linear-gradient(135deg, #111827 0%, #374151 100%);
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #FFFFFF;
  font-size: 18px;
  font-weight: 700;
  flex-shrink: 0;
}

.logo-text {
  font-size: 18px;
  font-weight: 700;
  color: #111827;
  white-space: nowrap;
  transition: color 0.3s;
}

body.dark-theme .logo-text {
  color: #ffffffd1;
}

.layout-menu {
  flex: 1;
  padding: 12px 8px;
  overflow-y: auto;
}

.layout-header {
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 20px;
  background: #FFFFFF;
  border-bottom: 1px solid #e8e8e8;
  transition: background-color 0.3s;
}

body.dark-theme .layout-header {
  background: #18181c;
  border-bottom: 1px solid #3f3f46;
}

// 顶栏应用主题色时的样式
.layout-header.header-primary {
  background: var(--primary-color) !important;
  border-bottom-color: var(--primary-color) !important;

  .header-icon {
    color: #fff;

    &:hover {
      background: rgba(255, 255, 255, 0.15);
    }
  }

  .user-info {
    &:hover {
      background: rgba(255, 255, 255, 0.15);
    }
  }

  .user-name {
    color: #fff;
  }

  :deep(.n-breadcrumb-item__link),
  :deep(.n-breadcrumb-item__separator) {
    color: rgba(255, 255, 255, 0.85) !important;
  }

  // 顶部菜单模式下的 logo 文字颜色
  .header-logo .logo-text {
    color: #fff;
  }
}

.header-left {
  display: flex;
  align-items: center;
}

.header-right {
  display: flex;
  align-items: center;
  gap: 16px;
}

.header-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.2s;

  &:hover {
    background: #F3F4F6;
  }
}

body.dark-theme .header-icon {
  &:hover {
    background: #3f3f46;
  }
}

.message-popover {
  margin: -12px;
}

.message-tabs {
  padding: 0 12px;
  border-bottom: 1px solid #e8e8e8;
}

.tab-text {
  display: inline-block;
  padding-top: 4px;
}

.message-list {
  max-height: 300px;
  overflow-y: auto;
  padding: 8px 0;
}

.message-list .message-item {
  padding: 12px 16px;
  cursor: pointer;
  transition: background 0.2s;
  border-bottom: 1px solid #f0f0f0;

  &:last-child {
    border-bottom: none;
  }

  &:hover {
    background: #f5f5f5;
  }
}

.message-item-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}

.message-item-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.message-item-content {
  flex: 1;
  min-width: 0;
}

.message-sender {
  font-size: 13px;
  font-weight: 500;
  color: #333;
}

.message-time {
  font-size: 11px;
  color: #999;
}

.message-list .message-title {
  font-size: 14px;
  font-weight: 500;
  color: #333;
  margin-bottom: 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.message-list .message-content {
  font-size: 12px;
  color: #666;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  line-height: 1.5;
}

.message-loading {
  padding: 12px;
  text-align: center;
}

.message-no-more {
  padding: 12px;
  text-align: center;
  font-size: 12px;
  color: #999;
}

.message-footer {
  padding: 12px 16px;
  text-align: center;
  border-top: 1px solid #e8e8e8;
  display: flex;
  justify-content: center;
  gap: 16px;
}

.user-info {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  padding: 6px 12px;
  border-radius: 8px;
  transition: background 0.2s;

  &:hover {
    background: #F3F4F6;
  }
}

body.dark-theme .user-info {
  &:hover {
    background: #3f3f46;
  }
}

.user-name {
  font-size: 14px;
  color: #1F2937;
  font-weight: 500;
}

body.dark-theme .user-name {
  color: #ffffffd1;
}

// 头部固定
.layout-header {
  position: sticky;
  top: 0;
  z-index: 100;
}

// 页签栏固定（紧跟在头部下方）
:deep(.tab-bar) {
  position: sticky;
  top: 60px; // header高度
  z-index: 99;
}

.layout-content {
  background: #F3F4F6;
  transition: background-color 0.3s;
}

body.dark-theme .layout-content {
  background: #101014;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.15s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

/* 搜索面板 */
.search-panel {
  margin: -12px;
  padding: 12px;
}

.search-results {
  margin-top: 12px;
  max-height: 300px;
  overflow-y: auto;
}

.search-result-item {
  display: flex;
  align-items: center;
  padding: 10px 12px;
  cursor: pointer;
  border-radius: 6px;
  transition: background 0.2s;

  &:hover {
    background: #f5f5f5;
  }
}

.result-icon {
  margin-right: 10px;
  color: #666;
}

.result-label {
  font-size: 14px;
  color: #333;
  flex: 1;
}

.result-path {
  font-size: 12px;
  color: #999;
}

/* 主题设置面板 */
.theme-panel {
  margin: -12px;
  padding: 16px;
}

.theme-section {
  margin-bottom: 20px;

  &:last-child {
    margin-bottom: 0;
  }
}

.theme-title {
  font-size: 14px;
  font-weight: 500;
  color: #333;
  margin-bottom: 12px;
}

body.dark-theme .theme-title {
  color: #ffffffd1;
}

.layout-options {
  display: flex;
  gap: 12px;
}

.layout-option {
  flex: 1;
  text-align: center;
  cursor: pointer;

  span {
    display: block;
    font-size: 12px;
    color: #666;
    margin-top: 8px;
  }

  &.active span {
    color: #18a058;
  }
}

.layout-preview {
  height: 48px;
  border: 2px solid #e8e8e8;
  border-radius: 4px;
  display: flex;
  overflow: hidden;

  .layout-option.active & {
    border-color: #60a5fa;
  }
}

body.dark-theme .layout-preview {
  border-color: #3f3f46;
  
  .layout-option.active & {
    border-color: #60a5fa;
  }
}

.layout-left {
  .preview-sider {
    width: 30%;
    background: #001529;
  }
  .preview-main {
    flex: 1;
    background: #f5f5f5;
  }
}

.layout-right {
  .preview-main {
    flex: 1;
    background: #f5f5f5;
  }
  .preview-sider {
    width: 30%;
    background: #001529;
  }
}

.layout-top {
  flex-direction: column;

  .preview-header {
    height: 30%;
    background: #001529;
  }
  .preview-content {
    flex: 1;
    background: #f5f5f5;
  }
}

.theme-switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.theme-modes {
  display: flex;
  gap: 16px;
}

.color-options {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.color-option {
  width: 24px;
  height: 24px;
  border-radius: 4px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;
  border: 2px solid transparent;

  &:hover {
    transform: scale(1.1);
  }

  &.active {
    border-color: #fff;
    box-shadow: 0 0 0 2px currentColor;
  }

  :deep(.n-icon) {
    font-size: 14px;
  }
}

.theme-mode {
  display: flex;
  flex-direction: column;
  align-items: center;
  cursor: pointer;

  span {
    font-size: 12px;
    color: #666;
    margin-top: 8px;
  }

  &.active span {
    color: #18a058;
    font-weight: 500;
  }
}

.theme-mode-preview {
  width: 48px;
  height: 48px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid #e8e8e8;
  transition: all 0.2s;

  .theme-mode:hover & {
    transform: scale(1.05);
  }

  .theme-mode.active & {
    border-color: #60a5fa;
  }
}

body.dark-theme .theme-mode-preview {
  border-color: #3f3f46;
  
  .theme-mode.active & {
    border-color: #60a5fa;
  }
}

body.dark-theme .theme-mode span {
  color: #ffffffa6;
}

body.dark-theme .theme-mode.active span {
  color: #60a5fa;
}

/* 右侧菜单样式 */
.sider-right {
  order: 1;
}

/* 顶部布局样式 */
.layout-top {
  flex-direction: column;

  .layout-header {
    flex-wrap: nowrap;
  }
}

.header-logo {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-right: 24px;

  .logo-icon {
    width: 32px;
    height: 32px;
    background: linear-gradient(135deg, #111827 0%, #374151 100%);
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #FFFFFF;
    font-size: 18px;
    font-weight: 700;
  }

  .logo-text {
    font-size: 18px;
    font-weight: 700;
    color: #111827;
    white-space: nowrap;
  }
}

.header-menu {
  flex: 1;
  overflow: hidden;

  :deep(.n-menu) {
    background: transparent;
  }
}

/* 主题风格 */
.theme-dark {
  background: #001529 !important;

  .logo-text {
    color: #fff;
  }

  :deep(.n-menu) {
    background: #001529;
    --n-item-text-color: rgba(255, 255, 255, 0.65);
    --n-item-text-color-hover: #fff;
    --n-item-text-color-active: #fff;
    --n-item-icon-color: rgba(255, 255, 255, 0.65);
    --n-item-icon-color-hover: #fff;
    --n-item-icon-color-active: #fff;
    --n-item-color-active: #18a058;
  }
}

.theme-light {
  background: #fff !important;
  border-right: 1px solid #e8e8e8;

  .logo-text {
    color: #333;
  }

  :deep(.n-menu) {
    background: #fff;
  }
}

// 暗色主题下的侧边栏样式覆盖
body.dark-theme .layout-sider {
  background: #18181c !important;
  border-right-color: #3f3f46 !important;
}

body.dark-theme .theme-light {
  background: #18181c !important;
  border-right: 1px solid #3f3f46;

  .logo-text {
    color: #ffffffd1;
  }

  .logo-icon {
    background: linear-gradient(135deg, #3f3f46 0%, #52525b 100%);
    color: #fff;
  }

  :deep(.n-menu) {
    background: #18181c;
    --n-item-text-color: rgba(255, 255, 255, 0.65);
    --n-item-text-color-hover: #fff;
    --n-item-text-color-active: #fff;
    --n-item-icon-color: rgba(255, 255, 255, 0.65);
    --n-item-icon-color-hover: #fff;
    --n-item-icon-color-active: #fff;
    --n-item-color-hover: #27272a;
    --n-item-color-active: #27272a;
    --n-item-color-active-hover: #3f3f46;
    --n-arrow-color: rgba(255, 255, 255, 0.5);
    --n-arrow-color-hover: rgba(255, 255, 255, 0.8);
    --n-arrow-color-active: rgba(255, 255, 255, 0.8);
  }
}

body.dark-theme .theme-dark {
  background: #101014 !important;

  :deep(.n-menu) {
    background: #101014;
  }
}

</style>
