<script setup>
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { LayoutDashboard, ScrollText, Settings, X, Database, SlidersHorizontal, Home, ListTodo, TicketCheck, CalendarDays, CalendarCheck2, Sparkles, UserRound, ClipboardList, Wrench, Rocket, ChevronDown, Bell, StickyNote, ListFilter, Palette, Bot, Users, NotebookPen, CloudUpload, Power } from 'lucide-vue-next'
import { useAppStore } from './store'
import DatabaseSetup from './components/DatabaseSetup.vue'
import BrowserBlocked from './components/BrowserBlocked.vue'
import AnalysisCanvas from './components/AnalysisCanvas.vue'
import LoginModal from './components/LoginModal.vue'
import CommandPalette from './components/CommandPalette.vue'
import DailyCard from './components/DailyCard.vue'
import AboutModal from './components/AboutModal.vue'
import MessageBell from './components/MessageBell.vue'
import TaskCenter from './components/TaskCenter.vue'
import NoteCenter from './components/NoteCenter.vue'
import TeamSwitcher from './components/TeamSwitcher.vue'
import TitleBar from './components/TitleBar.vue'
import { call, isNative, on } from './api'

const route = useRoute()
const router = useRouter()
const store = useAppStore()
const { t, locale } = useI18n()
const native = isNative()
const quickOpen = ref(false)
const aboutOpen = ref(false)
const appVersion = ref('1.0.0')
const displayedTask = ref(null)
let off
let offMenus = []
let loadingHoldTimer

const activeTask = computed(() => Object.values(store.tasks).find(x => !['completed', 'error', 'cancelled'].includes(x.stage)))
const visibleTask = computed(() => activeTask.value || displayedTask.value)
const activeTaskProject = computed(() => visibleTask.value?.params?.project || store.projects.find(p => p.id === visibleTask.value?.projectId)?.name || '')
const loadingStyle = computed(() => store.settings.loadingStyle === 'fullscreen' ? 'fullscreen-orbit' : (store.settings.loadingStyle || 'fullscreen-orbit'))
const useFullscreenLoading = computed(() => loadingStyle.value !== 'bar')

async function updateSetting(key, value) {
  const next = await store.saveSettings({ [key]: value })
  if (key === 'locale') locale.value = next.locale
}

function openSettings() {
  quickOpen.value = false
  router.push('/settings')
}

// 侧边栏底部退出：与原生菜单/托盘「退出」一致，绕过最小化到托盘直接退出应用。
async function quitApp() {
  if (!confirm(t('quitConfirm'))) return
  try { await call('QuitApp') } catch { /* 预览模式无原生桥 */ }
}

// ---- 双列导航：一级分类（rail）+ 二级菜单（sub），窄屏点一级弹浮层 ----
// 设置页无 query 时沿用本地记忆的分区，保证二级高亮与页面内容一致。
const settingsTab = r => String(r.query.tab || localStorage.getItem('cc-settings-tab') || 'rules')
const navGroups = [
  { id: 'overview', icon: Home, label: 'navOverview', items: [
    { to: '/', icon: Home, label: 'workbench', match: r => r.path === '/' },
    { to: '/today', icon: CalendarCheck2, label: 'todayTasks', badge: 'todayDue' },
    { to: '/calendar', icon: CalendarDays, label: 'calendar', dot: 'calendarDot' },
    { to: '/messages', icon: Bell, label: 'messages', badge: 'unread' }
  ] },
  { id: 'projects', icon: LayoutDashboard, label: 'navProjects', items: [
    { to: '/projects', icon: LayoutDashboard, label: 'projects', match: r => r.path === '/projects' || r.path.startsWith('/project/') },
    { to: '/ai', icon: Sparkles, label: 'aiChat' }
  ] },
  { id: 'work', icon: ClipboardList, label: 'navWork', items: [
    { to: '/todos', icon: ListTodo, label: 'todos', badge: 'todosOpen' },
    { to: '/tickets', icon: TicketCheck, label: 'tickets', badge: 'ticketsActive' },
    { to: '/notes', icon: StickyNote, label: 'notesPage' }
  ] },
  { id: 'team', icon: Users, label: 'navTeam', items: [
    { to: '/team', icon: Users, label: 'teamHome', match: r => r.path === '/team' },
    { to: '/team/tasks', icon: ClipboardList, label: 'teamTasks', badge: 'teamAssigned' },
    { to: '/team/reports', icon: NotebookPen, label: 'teamReports' }
  ] },
  { id: 'system', icon: Wrench, label: 'navSystem', items: [
    { to: '/launchpad', icon: Rocket, label: 'launchpad' },
    { to: '/logs', icon: ScrollText, label: 'logs' }
  ] },
  { id: 'settings', icon: Settings, label: 'settings', items: [
    { to: '/settings?tab=rules', icon: ListFilter, label: 'tabRules', match: r => r.path === '/settings' && settingsTab(r) === 'rules' },
    { to: '/settings?tab=appearance', icon: Palette, label: 'tabAppearance', match: r => r.path === '/settings' && settingsTab(r) === 'appearance' },
    { to: '/settings?tab=ai', icon: Bot, label: 'aiAnalysis', match: r => r.path === '/settings' && settingsTab(r) === 'ai' },
    // 全局文件存储配置：权威数据在服务器，仅管理员（云端账号 id=1）可见可改
    { to: '/settings?tab=filestorage', icon: CloudUpload, label: 'tabFileStorage', adminOnly: true, match: r => r.path === '/settings' && settingsTab(r) === 'filestorage' },
    { to: '/settings?tab=database', icon: Database, label: 'tabDatabase', match: r => r.path === '/settings' && settingsTab(r) === 'database' }
  ] }
]
// adminOnly 项只对云端管理员（id=1）展示
const visibleItems = g => g.items.filter(it => !it.adminOnly || store.syncStatus.userId === 1)
const itemActive = it => it.match ? it.match(route) : route.path === it.to.split('?')[0]
// 导航徽标：badge 显示数字，dot 只显示小圆点；一级 rail 在组内任一非零时亮点
const badgeVal = it => it.badge ? (store.badges[it.badge] || 0) : 0
const badgeText = it => { const n = badgeVal(it); return n > 99 ? '99+' : String(n) }
const dotVal = it => it.dot ? !!store.badges[it.dot] : false
const groupDot = g => g.items.some(it => badgeVal(it) > 0 || dotVal(it))
const childActive = c => route.path === '/settings' && String(route.query.tab || '') === c.tab
const groupOfRoute = () => navGroups.find(g => g.items.some(it => itemActive(it)))?.id
const activeGroupId = ref(groupOfRoute() || 'overview')
const activeGroup = computed(() => navGroups.find(g => g.id === activeGroupId.value) || navGroups[0])
const expandedParents = ref({})
const railFlyout = ref(null) // 窄屏浮层 { group, top }

watch(() => route.fullPath, () => {
  const g = groupOfRoute()
  if (g) activeGroupId.value = g
  railFlyout.value = null
  for (const grp of navGroups) {
    for (const it of grp.items) if (it.children && itemActive(it)) expandedParents.value[it.label] = true
  }
}, { immediate: true })

const isNarrow = () => window.matchMedia('(max-width: 1150px)').matches
function clickGroup(g, ev) {
  if (isNarrow()) {
    railFlyout.value = railFlyout.value?.group.id === g.id
      ? null
      : { group: g, top: Math.min(ev.currentTarget.getBoundingClientRect().top, innerHeight - 320) }
    return
  }
  activeGroupId.value = g.id
  const first = g.items[0]
  if (first && !itemActive(first)) router.push(first.to)
}
function toggleParent(it, ev) {
  ev.preventDefault()
  ev.stopPropagation()
  expandedParents.value[it.label] = !expandedParents.value[it.label]
}
function onFlyoutAway(e) {
  if (railFlyout.value && !e.target.closest('.rail-flyout') && !e.target.closest('.rail-item')) railFlyout.value = null
}

// Ctrl+K / Cmd+K 呼出全局搜索面板
function onGlobalKey(e) {
  if ((e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey && e.key.toLowerCase() === 'k') {
    e.preventDefault()
    store.paletteOpen = !store.paletteOpen
  }
}
onMounted(async () => {
  addEventListener('keydown', onGlobalKey)
  addEventListener('click', onFlyoutAway)
  if (!native) return
  off = store.listen()
  offMenus = [
    on('menu:navigate', p => router.push(String(p))),
    on('menu:action', k => {
      if (k === 'addProject') {
        store.pendingAction = 'addProject'
        router.push('/projects')
      } else if (k === 'account') {
        store.openAccount(router)
      } else if (k === 'about') {
        aboutOpen.value = true
      } else if (k === 'sync-refresh') {
        store.refreshSyncStatus()
      }
    }),
    on('menu:set', p => p?.key && updateSetting(p.key, p.value))
  ]
  await store.boot()
  locale.value = store.settings.locale || 'zh-CN'
  try { appVersion.value = await call('GetAppVersion') } catch { /* keep fallback */ }
})
onUnmounted(() => {
  removeEventListener('keydown', onGlobalKey)
  removeEventListener('click', onFlyoutAway)
  clearTimeout(loadingHoldTimer)
  off?.()
  offMenus.forEach(f => f?.())
})
watch(() => store.settings.locale, v => {
  if (v) locale.value = v
})
// 切页时顺带刷新同步徽标（待推送数在本地增删改后保持新鲜）
watch(() => route.path, () => { if (store.syncStatus.loggedIn) store.refreshSyncStatus() })
watch(activeTask, task => {
  clearTimeout(loadingHoldTimer)
  if (task) {
    displayedTask.value = task
    return
  }
  loadingHoldTimer = setTimeout(() => {
    displayedTask.value = null
  }, 900)
}, { immediate: true })
</script>

<template>
  <BrowserBlocked v-if="!native" />
  <template v-else>
    <TitleBar :app-version="appVersion" @about="aboutOpen = true" />
    <DatabaseSetup v-if="store.bootstrap.state !== 'ready' && store.bootstrap.state !== 'loading'" :status="store.bootstrap" class="with-titlebar" />
    <div v-else-if="store.bootstrap.state === 'ready'" class="shell">
    <aside class="sidebar">
      <div class="side-rail">
        <nav class="rail-nav" aria-label="Primary">
          <button v-for="g in navGroups" :key="g.id" type="button" class="rail-item" :class="{ active: g.id === activeGroupId }" @click="clickGroup(g, $event)">
            <component :is="g.icon" /><span>{{ t(g.label) }}</span>
            <i v-if="groupDot(g)" class="rail-dot" aria-hidden="true" />
          </button>
        </nav>
        <div class="rail-tools">
          <NoteCenter />
          <TaskCenter />
          <MessageBell />
          <TeamSwitcher />
        </div>
        <button class="rail-user" :class="{ active: route.path === '/profile' }" :title="store.syncStatus.loggedIn ? store.syncStatus.username : t('loginNow')" @click="store.openAccount(router)">
          <span class="user-avatar">
            <img v-if="store.avatarSrc" :src="store.avatarSrc" alt="" />
            <b v-else-if="store.syncStatus.username">{{ store.syncStatus.username[0].toUpperCase() }}</b>
            <UserRound v-else />
            <i v-if="store.syncStatus.loggedIn" class="user-dot" :class="store.syncStatus.lastError ? 'err' : (store.syncStatus.online ? 'on' : 'off')" :title="store.syncStatus.lastError || ''" />
          </span>
          <em v-if="store.syncStatus.loggedIn && store.syncStatus.pending > 0" class="user-pending rail-pending" :title="t('pendingSync', { n: store.syncStatus.pending })">{{ store.syncStatus.pending }}</em>
        </button>
      </div>
      <div class="side-sub">
        <div class="sub-brand"><b>{{ t('app') }}</b></div>
        <div class="sub-title">{{ t(activeGroup.label) }}</div>
        <nav class="sub-nav" :aria-label="t(activeGroup.label)">
          <template v-for="it in visibleItems(activeGroup)" :key="it.to">
            <RouterLink :to="it.to" :class="{ active: itemActive(it) }">
              <component :is="it.icon" /><span>{{ t(it.label) }}</span>
              <em v-if="badgeVal(it)" class="nav-badge">{{ badgeText(it) }}</em>
              <i v-else-if="dotVal(it)" class="nav-dot" aria-hidden="true" />
              <button v-if="it.children" type="button" class="sub-caret" :class="{ open: expandedParents[it.label] }" :aria-label="t(it.label)" @click="toggleParent(it, $event)"><ChevronDown /></button>
            </RouterLink>
            <div v-if="it.children && expandedParents[it.label]" class="sub-children">
              <RouterLink v-for="c in it.children" :key="c.to" :to="c.to" :class="{ active: childActive(c) }">{{ t(c.label) }}</RouterLink>
            </div>
          </template>
        </nav>
        <div class="sidebar-bottom">
          <span class="version"><i />v{{ appVersion }}</span>
          <button class="quick-settings-btn quit-app-btn" :title="t('quitApp')" :disabled="!native" @click="quitApp"><Power /></button>
          <button class="quick-settings-btn" :title="t('quickSettings')" @click="quickOpen = !quickOpen"><SlidersHorizontal /></button>
          <section v-if="quickOpen" class="quick-settings popover-glass">
          <header>
            <b>{{ t('quickSettings') }}</b>
            <button @click="quickOpen = false" aria-label="Close"><X /></button>
          </header>
          <label>
            <span>{{ t('language') }}</span>
            <select :value="store.settings.locale" @change="updateSetting('locale', $event.target.value)">
              <option value="zh-CN">中文</option>
              <option value="en">English</option>
            </select>
          </label>
          <label>
            <span>{{ t('theme') }}</span>
            <select :value="store.settings.theme" @change="updateSetting('theme', $event.target.value)">
              <option value="dark">{{ t('themeDark') }}</option>
              <option value="light">{{ t('themeLight') }}</option>
              <option value="system">{{ t('themeSystem') }}</option>
            </select>
          </label>
          <label>
            <span>{{ t('glassOpacity') }} · {{ store.settings.glassOpacity }}%</span>
            <input type="range" min="30" max="75" :value="store.settings.glassOpacity" @input="updateSetting('glassOpacity', Number($event.target.value))" />
          </label>
            <button class="btn secondary full" @click="openSettings"><Settings />{{ t('openSettings') }}</button>
          </section>
        </div>
      </div>
      <div v-if="railFlyout" class="rail-flyout popover-glass" :style="{ top: railFlyout.top + 'px' }">
        <b class="fly-title">{{ t(railFlyout.group.label) }}</b>
        <template v-for="it in visibleItems(railFlyout.group)" :key="it.to">
          <RouterLink :to="it.to" :class="{ active: itemActive(it) }">
            <component :is="it.icon" /><span>{{ t(it.label) }}</span>
            <em v-if="badgeVal(it)" class="nav-badge">{{ badgeText(it) }}</em>
            <i v-else-if="dotVal(it)" class="nav-dot" aria-hidden="true" />
          </RouterLink>
          <RouterLink v-for="c in it.children || []" :key="c.to" :to="c.to" class="fly-child" :class="{ active: childActive(c) }">{{ t(c.label) }}</RouterLink>
        </template>
      </div>
    </aside>
    <main><RouterView /></main>
    <div v-if="visibleTask && !useFullscreenLoading" class="taskbar">
      <div><b>{{ activeTaskProject || visibleTask.stage }}</b><span>{{ t(visibleTask.messageKey || 'task.start', visibleTask.params || {}) }}</span></div>
      <div class="progress"><i :style="{ width: visibleTask.progress + '%' }" /></div>
      <b>{{ visibleTask.progress }}%</b>
    </div>
    <div v-if="visibleTask && useFullscreenLoading" class="analysis-loading" :class="[loadingStyle, { holding: !activeTask }]">
      <AnalysisCanvas :progress="visibleTask.progress" :variant="loadingStyle" />
      <section>
        <b>{{ activeTaskProject || t('analyzingProject') }}</b>
        <span>{{ t(visibleTask.messageKey || 'task.start', visibleTask.params || {}) }}</span>
        <div class="progress"><i :style="{ width: visibleTask.progress + '%' }" /></div>
        <strong>{{ visibleTask.progress }}%</strong>
      </section>
    </div>
    <div v-if="store.toast" class="toast" :class="[store.toast.type, { muted: store.toast.muted, leaving: store.toast.leaving }]">
      {{ store.toast.key ? t(store.toast.key, store.toast.params || {}) : store.toast.text }}
      <button @click="store.closeToast()" aria-label="Close"><X /></button>
    </div>
    <LoginModal v-if="store.loginOpen" />
    <CommandPalette v-if="store.paletteOpen" />
    <AboutModal v-if="aboutOpen" @close="aboutOpen = false" />
    <DailyCard />
  </div>
    <div v-else class="boot-loading with-titlebar"><Database class="spin" />正在检查数据库...</div>
  </template>
</template>
