<template>
  <div class="min-h-screen flex relative dashboard-view" :class="{ 'glass-throw-active': showZoomIn }">
    <!-- Skip to main content link for keyboard users -->
    <!-- Skip-to-content handled by controller nav sidebar→main transition -->
    <!-- Background container with 3D perspective - full width to avoid letterboxing -->
    <div class="bg-perspective-container">
      <!-- Background - primary layer (visible for all routes, transitions out only for detail pages) -->
      <div
        ref="bgDefault"
        class="bg-layer bg-fullwidth"
        :class="[
          { 'bg-transitioning-out': showAltBackground },
          { 'zoom-reveal-bg': showZoomIn }
        ]"
        :style="{ backgroundImage: `url(/assets/img/${backgroundImage})` }"
      />
      <!-- Background - detail layer (only visible during app/marketplace detail 3D transition) -->
      <div
        ref="bgAlt"
        class="bg-layer bg-fullwidth"
        :class="{ 'bg-transitioning-in': showAltBackground }"
        style="background-image: url(/assets/img/bg-intro-3.jpg)"
      />
      <!-- Glitch overlays - trigger on background change -->
      <div
        class="bg-glitch-layer-1"
        :class="{ 'glitch-active': isGlitching }"
        :style="{ backgroundImage: `url(/assets/img/${backgroundImage})` }"
      />
      <div
        class="bg-glitch-layer-2"
        :class="{ 'glitch-active': isGlitching }"
        :style="{ backgroundImage: `url(/assets/img/${backgroundImage})` }"
      />
      <div
        class="bg-glitch-scan"
        :class="{ 'glitch-active': isGlitching }"
      />
      <!-- Glitch overlays removed — only intro glitch plays (via isGlitching) -->
    </div>

    <!-- Oomph accent - brief impact flash when dashboard loads -->
    <div
      v-if="showZoomIn"
      class="fixed inset-0 pointer-events-none z-[100] oomph-flash"
      aria-hidden="true"
    />
    <!-- Reveal flashes and glitch overlay - enthralling entrance -->
    <div
      v-if="showZoomIn"
      class="fixed inset-0 pointer-events-none z-[99] reveal-flash-glitch"
      aria-hidden="true"
    />

    <!-- Background overlay - uniform 0.2 opacity -->
    <div
      class="fixed inset-0 pointer-events-none bg-black/20"
      style="z-index: -5;"
    />

    <!-- Sidebar - Desktop Only -->
    <DashboardSidebar :show-zoom-in="showZoomIn" @logout="handleLogout" />

    <!-- Main Content (Xbox: Right goes here from sidebar) -->
    <main
      id="main-content"
      data-controller-zone="main"
      class="flex-1 overflow-hidden relative pb-0 glass-piece z-10"
      :class="{ 'glass-throw-main': showZoomIn }"
    >
      <div data-controller-main-entry class="absolute top-4 right-4 md:top-6 md:right-8 z-20">
        <!-- Controller zone entry point - no switcher -->
      </div>

      <!-- Connection Status Banners -->
      <ConnectionBanner />

      <div class="perspective-container-wrapper glass-piece" :class="{ 'glass-throw-content': showZoomIn && !isHomeRoute }">
        <div class="perspective-container">
          <RouterView v-slot="{ Component, route }">
            <Transition :name="getTransitionName(route)">
              <div :key="route.path" class="view-wrapper">
                <div
                  v-if="route.path === '/dashboard/chat' || route.path === '/dashboard/mesh'"
                  :class="['h-full', mobileTabPaddingTop ? 'overflow-y-auto' : '']"
                  :style="{ paddingTop: mobileTabPaddingTop ? (mobileTabPaddingTop + 16) + 'px' : undefined }"
                  class="mobile-safe-top"
                >
                  <component :is="Component" />
                </div>
                <div
                  v-else
                  :class="[
                    'absolute inset-0 px-4 pt-4 md:pt-8 md:px-8 overflow-y-auto mobile-safe-top',
                    needsMobileBackButtonSpace
                      ? 'mobile-scroll-pad-back'
                      : 'mobile-scroll-pad'
                  ]"
                  :style="mobileTabPaddingTop ? { paddingTop: (mobileTabPaddingTop + 16) + 'px' } : undefined"
                >
                  <component :is="Component" class="view-container flex-none" />
                  <!-- Bottom spacer — scroll clearance on all pages -->
                  <div class="shrink-0 h-6 md:h-12" aria-hidden="true"></div>
                </div>
              </div>
            </Transition>
          </RouterView>
        </div>
      </div>

      <!-- Panel mode app session — renders alongside current page content -->
      <Transition name="panel-slide">
        <div v-if="appLauncher.panelAppId" class="app-panel-container">
          <AppSession :app-id-prop="appLauncher.panelAppId" @close="appLauncher.closePanel()" />
        </div>
      </Transition>
    </main>

    <!-- Persistent Mobile Tabs + Bottom Tab Bar — outside <main> so position:fixed isn't broken by will-change:transform -->
    <DashboardMobileNav ref="mobileNavRef" :show-zoom-in="showZoomIn" />

    <!-- Health Notifications Toast -->
    <HealthNotifications />

    <!-- First-use companion intro overlay -->
    <CompanionIntroOverlay />
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch, nextTick, onMounted, onBeforeUnmount } from 'vue'
import { RouterView, useRouter, useRoute } from 'vue-router'
import { useAppStore } from '../stores/app'
import { useAppLauncherStore } from '../stores/appLauncher'
import AppSession from '@/views/AppSession.vue'
import { useLoginTransitionStore } from '../stores/loginTransition'
import { playDashboardLoadOomph } from '@/composables/useLoginSounds'

import DashboardSidebar from '@/views/dashboard/DashboardSidebar.vue'
import DashboardMobileNav from '@/views/dashboard/DashboardMobileNav.vue'
import ConnectionBanner from '@/views/dashboard/ConnectionBanner.vue'
import HealthNotifications from '@/views/dashboard/HealthNotifications.vue'
import CompanionIntroOverlay from '@/components/CompanionIntroOverlay.vue'
import { useRouteTransitions, isDetailRoute, ROUTE_BACKGROUNDS } from '@/views/dashboard/useRouteTransitions'
import '@/views/dashboard/dashboard-styles.css'

const router = useRouter()
const route = useRoute()
const store = useAppStore()
const appLauncher = useAppLauncherStore()
const loginTransition = useLoginTransitionStore()
const { getTransitionName } = useRouteTransitions()

const showZoomIn = ref(false)
const pendingTimers: ReturnType<typeof setTimeout>[] = []

function scheduledTimeout(fn: () => void, ms: number) {
  const id = setTimeout(fn, ms)
  pendingTimers.push(id)
  return id
}

const showAltBackground = ref(false)
const isHomeRoute = computed(() => route.path === '/dashboard' || route.path === '/dashboard/')
const isGlitching = ref(false)

const backgroundImage = computed(() => {
  const mapped = ROUTE_BACKGROUNDS[route.path]
  if (mapped) return mapped
  if (isDetailRoute(route.path)) return 'bg-intro.jpg'
  return 'bg-home.jpg'
})

const isDarkRoute = computed(() => {
  const p = route.path
  return p.includes('/dashboard/web5') ||
         p.includes('/dashboard/server') ||
         p.includes('/dashboard/settings') ||
         (p.includes('/dashboard/apps') && !isDetailRoute(p)) ||
         p.includes('/dashboard/marketplace') ||
         p.includes('/dashboard/discover') ||
         p.includes('/dashboard/cloud')
})

const showDarkOverlay = ref(isDarkRoute.value)
let overlayTimer: ReturnType<typeof setTimeout> | null = null

watch(isDarkRoute, (dark) => {
  if (overlayTimer) { clearTimeout(overlayTimer); overlayTimer = null }
  if (dark) {
    showDarkOverlay.value = true
  } else {
    overlayTimer = scheduledTimeout(() => { showDarkOverlay.value = false }, 450)
  }
})

const WEB5_DETAIL_ROUTES = ['/dashboard/server/federation', '/dashboard/monitoring', '/dashboard/fleet']
const needsMobileBackButtonSpace = computed(() =>
  isDetailRoute(route.path) || WEB5_DETAIL_ROUTES.includes(route.path)
)

const mobileNavRef = ref<InstanceType<typeof DashboardMobileNav> | null>(null)

const mobileTabPaddingTop = computed(() => {
  return mobileNavRef.value?.mobileTabPaddingTop ?? 0
})

// Scroll position save/restore — only restore when coming BACK from a detail page
const savedScrollPositions = new Map<string, number>()
let previousRoutePath = ''

function isAnyDetailRoute(path: string): boolean {
  return isDetailRoute(path) || WEB5_DETAIL_ROUTES.includes(path)
}

function saveCurrentScroll() {
  const el = document.querySelector<HTMLElement>('.perspective-container .view-wrapper > div[class*="overflow-y-auto"]')
  if (el && previousRoutePath) {
    savedScrollPositions.set(previousRoutePath, el.scrollTop)
  }
}

function restoreScroll(path: string) {
  const saved = savedScrollPositions.get(path)
  if (saved == null) return
  nextTick(() => {
    // Wait for transition to settle
    setTimeout(() => {
      const el = document.querySelector<HTMLElement>('.perspective-container .view-wrapper > div[class*="overflow-y-auto"]')
      if (el) el.scrollTop = saved
    }, 50)
  })
}

watch(() => route.path, (newPath) => {
  const isAppDetails = isDetailRoute(newPath)
  const wasAppDetails = showAltBackground.value
  const oldPath = previousRoutePath
  const wasDetail = isAnyDetailRoute(oldPath)
  const isDetail = isAnyDetailRoute(newPath)

  // Save scroll position of the page we're leaving
  saveCurrentScroll()

  // Restore scroll only when returning from a detail page to the parent list
  if (wasDetail && !isDetail) {
    restoreScroll(newPath)
  }

  previousRoutePath = newPath

  showAltBackground.value = isAppDetails

  if (isAppDetails && !wasAppDetails) {
    scheduledTimeout(() => {
      isGlitching.value = true
      scheduledTimeout(() => { isGlitching.value = false }, 375)
    }, 500)
  }
})

onMounted(() => {
  previousRoutePath = route.path
  document.body.classList.add('dashboard-active')
  if (loginTransition.justLoggedIn) {
    playDashboardLoadOomph()
    showZoomIn.value = true
    loginTransition.setPendingWelcomeTyping(true)
    loginTransition.setJustLoggedIn(false)
    const triggerRevealGlitch = () => {
      isGlitching.value = true
      scheduledTimeout(() => { isGlitching.value = false }, 380)
    }
    scheduledTimeout(triggerRevealGlitch, 500)
    scheduledTimeout(triggerRevealGlitch, 1200)
    scheduledTimeout(triggerRevealGlitch, 2000)
    scheduledTimeout(() => { showZoomIn.value = false }, 8000)
    scheduledTimeout(() => {
      loginTransition.setStartWelcomeTyping(true)
      loginTransition.setPendingWelcomeTyping(false)
    }, 4000)
  }

  window.addEventListener('keydown', handleKioskShortcuts)
})

onBeforeUnmount(() => {
  document.body.classList.remove('dashboard-active')
  window.removeEventListener('keydown', handleKioskShortcuts)
  for (const id of pendingTimers) clearTimeout(id)
  pendingTimers.length = 0
  if (overlayTimer) { clearTimeout(overlayTimer); overlayTimer = null }
})

function isKioskMode(): boolean {
  try {
    return localStorage.getItem('kiosk') === 'true' || new URLSearchParams(window.location.search).has('kiosk')
  } catch { return false }
}

function handleKioskShortcuts(e: KeyboardEvent) {
  if (!isKioskMode()) return
  if (e.ctrlKey && e.shiftKey) {
    if (e.key === 'R' || e.key === 'r') {
      e.preventDefault()
      router.push('/recovery')
    } else if (e.key === 'H' || e.key === 'h') {
      e.preventDefault()
      router.push('/dashboard')
    } else if (e.key === 'Q' || e.key === 'q') {
      e.preventDefault()
      if (confirm('Reboot the server?')) {
        fetch('/rpc/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ method: 'system.reboot' }) }).catch(() => {})
      }
    }
  }
}

async function handleLogout() {
  try {
    await store.logout()
  } catch {
    /* proceed to login regardless */
  }
  router.push('/login').catch(() => {
    window.location.href = '/login'
  })
}
</script>

<!-- Styles extracted to dashboard/dashboard-styles.css -->
