<script setup lang="ts">
/**
 * DashboardLayout — game-aware app shell (Phase C redesign).
 * Nav is driven by GAME_PROFILES[activeGame].nav — switching the GameSwitcher
 * visibly changes nav items, labels, and sections per game.
 * Preserves: permission gating, super-admin section, logout, mobile sidebar,
 * GameSwitcher, agent-health footer, topbar.
 */
import { ref, computed, watch, onMounted } from 'vue'
import { RouterView, useRoute, useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { useFleetStore } from '@/stores/fleet'
import { useThemeGame, syncActiveGameFromFleet } from '@/composables/useThemeGame'
import { useGameProfile } from '@/config/gameProfiles'
import type { NavSection, NavItemDef } from '@/config/gameProfiles'
import { safeDate } from '@/utils/formatters'
import ErrorBoundary from '@/components/ErrorBoundary.vue'
import Logo from '@/components/ds/brand/Logo.vue'
import Badge from '@/components/ds/core/Badge.vue'
import StatusDot from '@/components/ds/core/StatusDot.vue'
import IconButton from '@/components/ds/core/IconButton.vue'
import Button from '@/components/ds/core/Button.vue'
import Avatar from '@/components/ds/data/Avatar.vue'
import NavItem from '@/components/ds/navigation/NavItem.vue'
import GameSwitcher from '@/components/ds/navigation/GameSwitcher.vue'
import type { GameOption } from '@/components/ds/navigation/GameSwitcher.vue'
import type { ActiveGame } from '@/composables/useThemeGame'

// ---- Stores / composables ----
const route = useRoute()
const router = useRouter()
const auth = useAuthStore()
const fleet = useFleetStore()
const { theme, activeGame, setActiveGame, toggleTheme } = useThemeGame()

// ---- Active game follows the deployed fleet (instances are the source of
// truth for which game a license runs). A manual GameSwitcher pick overrides
// this; see syncActiveGameFromFleet. ----
const deployedGames = computed(() =>
  fleet.hosts.flatMap((h) => h.instances.map((i) => i.game)),
)
watch(deployedGames, (games) => syncActiveGameFromFleet(games), { immediate: true })
onMounted(() => { if (!fleet.hosts.length) void fleet.fetchFleet() })

// ---- Mobile sidebar ----
const sidebarOpen = ref(false)
function closeSidebar() { sidebarOpen.value = false }

// ---- App version ----
const APP_VERSION = __APP_VERSION__

// ---- Game switcher ----
const GAME_OPTIONS: GameOption[] = [
  { key: 'all',      label: 'All games',     icon: 'layers' },
  { key: 'rust',     label: 'Rust',          icon: 'box' },
  { key: 'dune',     label: 'Dune',          icon: 'sun' },
  { key: 'conan',    label: 'Conan Exiles',  icon: 'swords' },
  { key: 'soulmask', label: 'Soulmask',      icon: 'drama' },
]

const GAME_LABEL: Record<string, string> = {
  all: 'All games', rust: 'Rust', dune: 'Dune',
  conan: 'Conan Exiles', soulmask: 'Soulmask',
}

function onActiveGame(val: string) {
  setActiveGame(val as ActiveGame)
}

// ---- Navigation — driven by the game profile registry ----
/**
 * For 'all', fall back to rust (superset nav). For a specific game, look up
 * its profile. noUncheckedIndexedAccess-safe: always ?? GAME_PROFILES.rust.
 */
const activeNavSections = computed<NavSection[]>(() => {
  const game = activeGame.value === 'all' ? 'rust' : activeGame.value
  return (useGameProfile(game)).nav
})

const adminNavItems = [
  { name: 'Admin home', path: '/admin', icon: 'shield' },
  { name: 'Licenses', path: '/admin/licenses', icon: 'key' },
  { name: 'Subscriptions', path: '/admin/subscriptions', icon: 'credit-card' },
  { name: 'Users', path: '/admin/users', icon: 'users' },
  { name: 'Server fleet', path: '/admin/servers', icon: 'server' },
]

function isActive(path: string): boolean {
  if (path === '/' || path === '/admin') return route.path === path
  return route.path.startsWith(path)
}

function navigate(path: string) {
  router.push(path)
  closeSidebar()
}

function canShowNavItem(item: NavItemDef): boolean {
  if (!item.permission) return true
  return auth.hasPermission(item.permission)
}

function hasVisibleItems(section: NavSection): boolean {
  return section.items.some(canShowNavItem)
}

// ---- Agent health — driven by the fleet, not the legacy single connection ----
// Real hosts only (the fleet response appends a synthetic '__unassigned__'
// bucket for orphaned instances; summary counts already exclude it).
const realHosts = computed(() => fleet.hosts.filter((h) => h.id !== '__unassigned__'))
const hostCount = computed(() => fleet.summary.host_count)
const onlineHosts = computed(() => fleet.summary.online_host_count)
const instanceCount = computed(() => fleet.summary.instance_count)

const hasAgent = computed(() => hostCount.value > 0)

const agentTone = computed(() => {
  if (onlineHosts.value === 0) return 'offline' as const
  if (onlineHosts.value < hostCount.value) return 'warn' as const
  return 'online' as const
})
const agentLabel = computed(() => {
  if (onlineHosts.value === 0) return 'Offline'
  if (onlineHosts.value < hostCount.value) return 'Degraded'
  return 'Healthy'
})
// One host → its hostname; multiple → fleet count.
const agentName = computed(() =>
  hostCount.value === 1 ? (realHosts.value[0]?.hostname ?? 're-Agent') : `${hostCount.value} hosts`,
)

const agentMetaLine = computed(() => {
  const insts = `${instanceCount.value} ${instanceCount.value === 1 ? 'instance' : 'instances'}`
  if (hostCount.value === 1) {
    const h = realHosts.value[0]
    const state = h?.status === 'connected'
      ? 'Connected'
      : h?.last_heartbeat_at
        ? `Last seen ${safeDate(h.last_heartbeat_at)}`
        : 'Awaiting first heartbeat'
    return `${state} · ${insts}`
  }
  return `${onlineHosts.value}/${hostCount.value} online · ${insts}`
})

// ---- Topbar ----
const serverName = computed(() => auth.license?.server_name ?? 'Your servers')
const userName = computed(() => auth.user?.username ?? '')
const themeIcon = computed(() => theme.value === 'dark' ? 'sun' : 'moon')
</script>

<template>
  <!-- Outer app grid: sidebar | main -->
  <div class="app">
    <!-- ===================================================== SIDEBAR ===== -->
    <!-- Mobile overlay -->
    <div
      v-if="sidebarOpen"
      class="sidebar-overlay"
      @click="closeSidebar"
    />

    <aside
      class="app__sidebar"
      :class="sidebarOpen ? 'app__sidebar--open' : ''"
    >
      <!-- Brand -->
      <div class="side__brand">
        <Logo :size="22" />
        <Badge tone="neutral" :mono="true" class="side__ver">{{ APP_VERSION }}</Badge>
      </div>

      <!-- Active game switcher -->
      <div class="side__game">
        <div class="t-eyebrow side__lbl">
          Active game · {{ GAME_LABEL[activeGame] ?? 'All games' }}
        </div>
        <GameSwitcher
          :model-value="activeGame"
          :games="GAME_OPTIONS"
          :show-labels="false"
          @update:model-value="onActiveGame"
        />
      </div>

      <!-- Navigation — sections driven by GAME_PROFILES[activeGame].nav -->
      <nav class="side__nav">
        <template v-for="section in activeNavSections" :key="section.label">
          <template v-if="hasVisibleItems(section)">
            <div class="side__sec">
              <div v-if="section.label" class="t-eyebrow side__lbl">{{ section.label }}</div>
              <NavItem
                v-for="item in section.items"
                v-show="canShowNavItem(item)"
                :key="item.route"
                :icon="item.icon"
                :label="item.label"
                :active="isActive(item.route)"
                @click="navigate(item.route)"
              />
            </div>
          </template>
        </template>

        <!-- Platform admin section (super-admin only) -->
        <div v-if="auth.isSuperAdmin" class="side__sec">
          <div class="t-eyebrow side__lbl side__lbl--platform">Platform</div>
          <NavItem
            v-for="item in adminNavItems"
            :key="item.path"
            :icon="item.icon"
            :label="item.name"
            :active="isActive(item.path)"
            @click="navigate(item.path)"
          />
        </div>
      </nav>

      <!-- Host agent footer -->
      <div class="side__foot">
        <!-- Connected: real IP + status badge + meta line -->
        <div v-if="hasAgent" class="agent">
          <div class="agent__row">
            <StatusDot :tone="agentTone" :pulse="agentTone === 'online'" />
            <span class="agent__name">{{ agentName }}</span>
            <Badge :tone="agentTone" size="md">{{ agentLabel }}</Badge>
          </div>
          <div class="agent__meta">{{ agentMetaLine }}</div>
        </div>
        <!-- Not connected: honest empty state -->
        <div v-else class="agent agent--empty">
          <div class="agent__row">
            <StatusDot tone="offline" />
            <span class="agent__name agent__name--muted">No re-Agent connected</span>
          </div>
          <div class="agent__meta">Install re-Agent from the Server page</div>
        </div>
        <!-- User / logout row -->
        <div class="side__user">
          <span class="side__user-name">{{ auth.user?.username ?? '' }}</span>
          <button
            type="button"
            class="side__logout"
            title="Sign out"
            @click="() => { auth.logout(); router.push('/login') }"
          >
            <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
              <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/>
            </svg>
          </button>
        </div>
      </div>
    </aside>

    <!-- ======================================================= MAIN ===== -->
    <div class="app__main">
      <!-- Topbar -->
      <header class="app__topbar">
        <!-- Mobile hamburger (left of topbar on small screens) -->
        <button
          class="topbar-hamburger"
          type="button"
          aria-label="Open navigation"
          @click="sidebarOpen = true"
        >
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
            <line x1="3" y1="6" x2="21" y2="6" />
            <line x1="3" y1="12" x2="21" y2="12" />
            <line x1="3" y1="18" x2="21" y2="18" />
          </svg>
        </button>

        <!-- Breadcrumb -->
        <div class="top__crumbs">
          <span class="crumb">Catalyst</span>
          <span class="crumb__sep">/</span>
          <span class="crumb crumb--cluster">{{ serverName }}</span>
        </div>

        <!-- Actions -->
        <div class="top__actions">
          <IconButton
            :icon="themeIcon"
            label="Toggle theme"
            @click="toggleTheme"
          />
          <IconButton icon="bell" label="Alerts" @click="router.push('/alerts')" />
          <Button size="sm" icon="rocket" @click="router.push('/server')">Deploy server</Button>
          <Avatar
            :name="userName"
            :size="30"
            status="online"
          />
        </div>
      </header>

      <!-- Page content — boundary keeps sidebar/topbar alive when a view fails -->
      <main class="app__content">
        <ErrorBoundary variant="content">
          <RouterView />
        </ErrorBoundary>
      </main>
    </div>
  </div>
</template>

<style>
/* ============================================================ SHELL ===== */
html, body { height: 100%; }
body { margin: 0; overflow: hidden; }

.app {
  display: grid;
  grid-template-columns: var(--sidebar-w, 228px) 1fr;
  height: 100vh;
  background: var(--surface-canvas, #0a0a0b);
}

/* ---- Sidebar ---- */
.app__sidebar {
  background: var(--surface-base);
  border-right: 1px solid var(--border-subtle);
  display: flex;
  flex-direction: column;
  min-height: 0;
  z-index: 50;
}

.side__brand {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 15px 16px 12px;
}

.side__ver {
  font-family: var(--font-mono);
}

.side__game {
  padding: 2px 14px 13px;
  border-bottom: 1px solid var(--border-subtle);
}

.side__lbl {
  margin-bottom: 7px;
}

.side__lbl--platform {
  color: var(--accent-text);
}

.side__nav {
  flex: 1;
  overflow-y: auto;
  padding: 13px 10px;
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.side__sec {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.side__sec .t-eyebrow {
  margin: 0 0 5px 10px;
}

.side__foot {
  padding: 11px;
  border-top: 1px solid var(--border-subtle);
}

.agent {
  background: var(--surface-raised);
  border-radius: var(--radius-md);
  box-shadow: var(--ring-default);
  padding: 9px 11px;
}

.agent__row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.agent__name {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-primary);
  flex: 1;
}

.agent__meta {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-muted);
  margin-top: 5px;
  padding-left: 16px;
}

.agent--empty { opacity: 0.7; }

.agent__name--muted {
  color: var(--text-tertiary);
  font-style: italic;
}

.side__user {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 8px;
  padding: 4px 2px 0;
}

.side__user-name {
  font-size: var(--text-xs);
  color: var(--text-tertiary);
  font-family: var(--font-mono);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.side__logout {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 0;
  background: transparent;
  color: var(--text-muted);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: var(--transition-colors);
  flex: none;
}
.side__logout:hover { background: var(--surface-hover); color: var(--text-primary); }

/* ---- Main ---- */
.app__main {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

.app__topbar {
  height: var(--topbar-h, 52px);
  flex: none;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 0 18px;
  border-bottom: 1px solid var(--border-subtle);
  background: var(--surface-base);
}

.top__crumbs {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: var(--text-sm);
}

.crumb { color: var(--text-tertiary); }
.crumb__sep { color: var(--text-muted); }
.crumb--cluster {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text-primary);
  font-weight: 600;
  background: var(--surface-raised-2);
  border: 0;
  box-shadow: var(--ring-default);
  height: 30px;
  padding: 0 10px;
  border-radius: var(--radius-md);
  font-family: var(--font-sans);
}

.top__search {
  flex: 1;
  max-width: 440px;
  display: flex;
  align-items: center;
  gap: 9px;
  height: 34px;
  padding: 0 11px;
  background: var(--surface-inset);
  border-radius: var(--radius-md);
  box-shadow: var(--ring-default);
  color: var(--text-tertiary);
}

.top__search-icon { flex: none; }

.top__search input {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: 0;
  outline: 0;
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-sm);
  cursor: default;
}

.top__search input::placeholder { color: var(--text-muted); }

.top__kbd { display: flex; gap: 3px; }

.top__actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

.app__content {
  flex: 1;
  overflow-y: auto;
  padding: 22px 24px 40px;
}

/* ---- Mobile hamburger ---- */
.topbar-hamburger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border: 0;
  background: transparent;
  color: var(--text-secondary);
  border-radius: var(--radius-md);
  cursor: pointer;
  flex: none;
}
.topbar-hamburger:hover { background: var(--surface-hover); color: var(--text-primary); }

/* ---- Sidebar overlay (mobile) ---- */
.sidebar-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 49;
}

/* ---- Kbd styling ---- */
.cc-kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 4px;
  background: var(--surface-active);
  border-radius: var(--radius-xs, 3px);
  box-shadow: var(--ring-default);
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 600;
  color: var(--text-secondary);
  line-height: 1;
}

/* ---- Responsive ---- */
@media (max-width: 900px) {
  .app {
    grid-template-columns: 1fr;
  }

  .app__sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: 228px;
    transform: translateX(-100%);
    transition: transform 220ms cubic-bezier(0.2, 0, 0, 1);
  }

  .app__sidebar--open {
    transform: translateX(0);
  }

  .sidebar-overlay {
    display: block;
  }

  .topbar-hamburger {
    display: inline-flex;
  }

  .top__search {
    display: none;
  }
}
</style>
