<template>
  <v-app>
    <!-- ── App Bar (隐藏于登录页) ── -->
    <v-app-bar v-if="auth.isLoggedIn" color="primary" elevation="0" flat class="ps-4">
      <v-app-bar-nav-icon class="mr-3" @click="drawer = !drawer" />

      <v-avatar color="surface" size="40" class="pa-1">
        <v-icon icon="mdi-server-network" size="24" />
      </v-avatar>

      <v-app-bar-title>Nexus</v-app-bar-title>

      <!-- ── Global Search ── -->
      <v-text-field
        v-if="auth.isLoggedIn"
        v-model="searchQuery"
        prepend-inner-icon="mdi-magnify"
        append-inner-icon="mdi-close"
        placeholder="搜索服务器、脚本、凭据..."
        variant="solo-inverted"
        density="compact"
        hide-details
        rounded
        clearable
        class="mx-4"
        style="max-width: 360px"
        @click:append-inner="clearSearch"
        @click:clear="clearSearch"
        @update:model-value="onSearchInput"
      />

      <v-menu
        v-model="searchMenuOpen"
        :close-on-content-click="false"
        activator="parent"
        location="bottom"
        :open-on-click="false"
        :open-on-focus="false"
      >
        <v-card v-if="searchResults && searchResults.total > 0" width="420" elevation="8" rounded="lg" class="mt-1">
          <v-list density="compact" slim>
            <!-- Servers -->
            <template v-if="searchResults.servers.length">
              <v-list-subheader>
                <v-icon size="14" class="mr-1">mdi-server</v-icon>
                服务器 ({{ searchResults.servers.length }})
              </v-list-subheader>
              <v-list-item
                v-for="s in searchResults.servers"
                :key="'s-' + s.id"
                :title="s.name"
                :subtitle="s.domain"
                prepend-icon="mdi-server"
                slim
                link
                @click="goToServer(s.id)"
              />
            </template>

            <!-- Scripts -->
            <template v-if="searchResults.scripts.length">
              <v-divider v-if="searchResults.servers.length" />
              <v-list-subheader>
                <v-icon size="14" class="mr-1">mdi-code-braces</v-icon>
                脚本 ({{ searchResults.scripts.length }})
              </v-list-subheader>
              <v-list-item
                v-for="s in searchResults.scripts"
                :key="'sc-' + s.id"
                :title="s.name"
                :subtitle="s.category || '—'"
                prepend-icon="mdi-code-braces"
                slim
                link
                @click="goToScripts()"
              />
            </template>

            <!-- Credentials -->
            <template v-if="searchResults.credentials.length">
              <v-divider v-if="searchResults.servers.length || searchResults.scripts.length" />
              <v-list-subheader>
                <v-icon size="14" class="mr-1">mdi-key</v-icon>
                凭据 ({{ searchResults.credentials.length }})
              </v-list-subheader>
              <v-list-item
                v-for="c in searchResults.credentials"
                :key="'c-' + c.id"
                :title="c.name"
                :subtitle="`${c.db_type} @ ${c.host}`"
                prepend-icon="mdi-key"
                slim
                link
                @click="goToCredentials()"
              />
            </template>

            <!-- Schedules -->
            <template v-if="searchResults.schedules.length">
              <v-divider v-if="searchResults.servers.length || searchResults.scripts.length || searchResults.credentials.length" />
              <v-list-subheader>
                <v-icon size="14" class="mr-1">mdi-clock</v-icon>
                调度 ({{ searchResults.schedules.length }})
              </v-list-subheader>
              <v-list-item
                v-for="s in searchResults.schedules"
                :key="'sch-' + s.id"
                :title="s.name"
                :subtitle="s.cron_expr"
                prepend-icon="mdi-clock"
                slim
                link
                @click="goToSchedules()"
              />
            </template>
          </v-list>
        </v-card>

        <!-- No results -->
        <v-card v-else-if="searchQuery && searchQuery.length >= 2 && !searchLoading" width="420" elevation="8" rounded="lg" class="mt-1">
          <v-card-text class="text-center text-medium-emphasis py-6">
            <v-icon size="32" class="mb-2">mdi-magnify-close</v-icon>
            <div>未找到匹配结果</div>
          </v-card-text>
        </v-card>
      </v-menu>

      <template #append>
        <v-btn class="text-none me-1 px-3" height="48" slim>
          <template #prepend>
            <v-avatar color="surface-light" size="32" start>
              <v-icon icon="mdi-account" size="18" />
            </v-avatar>
          </template>

          <span class="hidden-sm-and-down">{{ auth.admin?.username || '管理员' }}</span>

          <v-menu activator="parent">
            <v-list density="compact" nav>
              <v-list-item
                prepend-icon="mdi-theme-light-dark"
                title="切换主题"
                link
                @click="toggleTheme"
              />
              <v-list-item
                prepend-icon="mdi-cog-outline"
                title="设置"
                link
                @click="router.push('/settings')"
              />
              <v-list-item
                prepend-icon="mdi-logout"
                title="退出登录"
                link
                @click="doLogout"
              />
            </v-list>
          </v-menu>

          <template #append>
            <v-icon icon="mdi-chevron-down" />
          </template>
        </v-btn>
      </template>
    </v-app-bar>

    <!-- ── Navigation Drawer (隐藏于登录页) ── -->
    <v-navigation-drawer
      v-if="auth.isLoggedIn"
      v-model="drawer"
      color="surface"
      width="250"
      class="nexus-nav-drawer"
      :temporary="mobile"
    >
      <v-list nav slim>
        <v-list-subheader>运维</v-list-subheader>

        <v-list-item
          v-for="item in opsItems"
          :key="item.to"
          :prepend-icon="item.icon"
          :title="item.title"
          :to="item.to"
          :active="route.path === item.to"
          active-class="text-primary"
          link
          nav
          slim
          @click="navigateTo(item.to)"
        />
      </v-list>

      <v-divider class="mx-3 my-1" />

      <v-list nav slim>
        <v-list-subheader>系统</v-list-subheader>

        <v-list-item
          v-for="item in sysItems"
          :key="item.to"
          :prepend-icon="item.icon"
          :title="item.title"
          :to="item.to"
          :active="route.path === item.to"
          active-class="text-primary"
          link
          nav
          slim
          @click="navigateTo(item.to)"
        />
      </v-list>

      <template #append>
        <v-list-item
          :active="route.path === '/settings'"
          prepend-icon="mdi-cog-outline"
          title="设置"
          active-class="text-primary"
          class="ma-2"
          link
          nav
          slim
          @click="router.push('/settings')"
        />
      </template>
    </v-navigation-drawer>

    <!-- ── Main Content ── -->
    <v-main :class="mainLayoutClass">
      <router-view :key="route.fullPath" />
    </v-main>

    <!-- ── Snackbar ── -->
    <v-snackbar v-model="snackbar.show" :color="snackbar.color" :timeout="3000" location="top right">
      {{ snackbar.text }}
    </v-snackbar>
  </v-app>
</template>

<script setup lang="ts">
import { ref, reactive, watch, onUnmounted, provide, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useTheme, useDisplay } from 'vuetify'
import { useAuthStore } from '@/stores/auth'
import { useWebSocket } from '@/composables/useWebSocket'
import { api, http } from '@/api'

const route = useRoute()
const router = useRouter()
const theme = useTheme()
const auth = useAuthStore()
const ws = useWebSocket()

// Auto-connect WebSocket when logged in
watch(() => auth.isLoggedIn, (loggedIn) => {
  if (loggedIn) { ws.connect(); syncThemeFromServer() }
  else ws.disconnect()
}, { immediate: true })

// ── Theme: localStorage + MySQL ──
async function syncThemeFromServer() {
  if (!auth.isLoggedIn) return
  try {
    const data = await api<{ value: string }>('/settings/theme')
    if (data.value === 'dark' || data.value === 'light') {
      theme.global.name.value = data.value
      localStorage.setItem('nexus_theme', data.value)
    }
  } catch { /* non-critical — keep localStorage value */ }
}

async function toggleTheme() {
  const newTheme = theme.global.current.value.dark ? 'light' : 'dark'
  theme.global.name.value = newTheme
  localStorage.setItem('nexus_theme', newTheme)
  // Persist to MySQL (fire-and-forget)
  try {
    await api('/settings/theme', { method: 'PUT', body: JSON.stringify({ value: newTheme }) })
  } catch { /* keep localStorage as fallback */ }
}

const drawer = ref(true)
const { mobile } = useDisplay()

/** 终端页监听菜单开合，在动画结束后 refit xterm */
provide('nexusDrawer', drawer)

const mainLayoutClass = computed(() => ({
  'nexus-terminal-main': route.path === '/terminal',
  'nexus-page-main': route.path !== '/terminal' && route.path !== '/login',
}))

const opsItems = [
  { to: '/',          title: '仪表盘',   icon: 'mdi-view-dashboard-outline' },
  { to: '/servers',   title: '服务器',   icon: 'mdi-server' },
  { to: '/terminal',  title: '终端',     icon: 'mdi-console' },
  { to: '/files',     title: '文件管理', icon: 'mdi-folder-outline' },
  { to: '/push',      title: '推送',     icon: 'mdi-upload-outline' },
  { to: '/scripts',   title: '脚本库',   icon: 'mdi-code-braces' },
  { to: '/credentials',title: '凭据',   icon: 'mdi-key-outline' },
  { to: '/schedules', title: '调度',     icon: 'mdi-clock-outline' },
  { to: '/retries',   title: '重试队列', icon: 'mdi-refresh' },
]

const sysItems = [
  { to: '/commands', title: '命令日志', icon: 'mdi-console' },
  { to: '/alerts',   title: '告警中心', icon: 'mdi-bell-outline' },
  { to: '/audit',    title: '审计日志', icon: 'mdi-clipboard-text-outline' },
]

const snackbar = reactive({ show: false, text: '', color: 'success' })

// ── Global Search ──
const searchQuery = ref('')
const searchMenuOpen = ref(false)
const searchLoading = ref(false)
const searchResults = ref<SearchResults | null>(null)

let searchTimer: ReturnType<typeof setTimeout>

function onSearchInput() {
  clearTimeout(searchTimer)
  if (!searchQuery.value || searchQuery.value.length < 2) {
    searchResults.value = null
    searchMenuOpen.value = false
    return
  }
  searchTimer = setTimeout(() => doSearch(), 300)
}

async function doSearch() {
  if (!searchQuery.value || searchQuery.value.length < 2) return
  searchLoading.value = true
  searchMenuOpen.value = true
  try {
    const res = await http.get<SearchResults>('/search/', { q: searchQuery.value })
    searchResults.value = res
    if (res.total === 0) searchMenuOpen.value = true
  } catch {
    searchResults.value = null
  } finally {
    searchLoading.value = false
  }
}

function clearSearch() {
  searchQuery.value = ''
  searchResults.value = null
  searchMenuOpen.value = false
}

function goToServer(id: number) {
  searchMenuOpen.value = false
  router.push({ path: '/servers', query: { highlight: String(id) } })
}
function goToScripts() {
  searchMenuOpen.value = false
  router.push('/scripts')
}
function goToCredentials() {
  searchMenuOpen.value = false
  router.push('/credentials')
}
function goToSchedules() {
  searchMenuOpen.value = false
  navigateTo('/schedules')
}

function navigateTo(to: string) {
  if (route.path !== to) {
    router.push(to).catch(() => {})
  }
  if (mobile.value) {
    drawer.value = false
  }
}

// ── Theme ──
// See toggleTheme() above — persists to both localStorage and MySQL


function doLogout() {
  auth.logout()
  router.push('/login')
}

// Expose snackbar globally
window.$snackbar = (text: string, color = 'success') => {
  snackbar.text = text
  snackbar.color = color
  snackbar.show = true
}

// Cleanup
onUnmounted(() => clearTimeout(searchTimer))

interface SearchResults {
  servers: { id: number; name: string; domain: string; category: string | null; is_online: boolean }[]
  scripts: { id: number; name: string; category: string | null }[]
  credentials: { id: number; name: string; db_type: string; host: string }[]
  schedules: { id: number; name: string; cron_expr: string; enabled: boolean }[]
  total: number
  query: string
}
</script>

<style>
/*
 * 终端页：高度占满内容区；宽度随 --v-layout-left 随侧栏开合自动缩进（勿 padding:0）
 */
.v-application .v-main.nexus-terminal-main {
  display: flex;
  flex-direction: column;
  height: calc(100dvh - var(--v-layout-top, 64px));
  min-height: 0;
  max-width: 100%;
  overflow: hidden;
  box-sizing: border-box;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  transition:
    padding 0.2s cubic-bezier(0.4, 0, 0.2, 1),
    height 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.v-application .v-main.nexus-terminal-main > .v-container {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  max-width: 100%;
  width: 100%;
  padding: 0;
}

/* 仪表盘等业务页：随侧栏 --v-layout-left 缩进，表格可横向滚动 */
.v-application .v-main.nexus-page-main {
  box-sizing: border-box;
  min-height: calc(100dvh - var(--v-layout-top, 64px));
  min-width: 0;
  max-width: 100%;
  overflow-x: hidden;
  transition: padding 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.v-application .v-main.nexus-page-main > * {
  min-width: 0;
  max-width: 100%;
}

/* 侧栏菜单项过多时可滚动，避免「调度/重试队列」在视口外无法点击 */
.nexus-nav-drawer :deep(.v-navigation-drawer__content) {
  overflow-y: auto;
}
</style>
