<template>
  <a-spin :spinning="spinning" size="large" tip="加载中..." class="layout-spin">
    <a-layout class="min-h-screen layout-shell" :class="{ 'layout-shell--pending': spinning }">
      <SiteHeader />
      <a-layout-content class="content">
        <slot />
      </a-layout-content>
      <SiteFooter />
    </a-layout>
  </a-spin>
</template>

<script setup lang="ts">
import SiteFooter from '@/components/SiteFooter.vue'
import SiteHeader from '@/components/SiteHeader.vue'
import { nextTick } from 'vue'

const nuxtApp = useNuxtApp()
const bootstrapping = ref(true)
const navigating = ref(false)
const siteInfoTimeoutReached = ref(false)

const { pending: siteInfoPending, error: siteInfoError } = useSiteInfo()

const siteInfoBlocking = computed(
  () => siteInfoPending.value && !siteInfoError.value && !siteInfoTimeoutReached.value
)

const spinning = computed(() => bootstrapping.value || navigating.value || siteInfoBlocking.value)

if (import.meta.client) {
  nuxtApp.hooks.hook('page:start', () => {
    navigating.value = true
  })

  nuxtApp.hooks.hook('page:finish', () => {
    navigating.value = false
  })

  onMounted(async () => {
    // Wait for hydration + one paint to reduce CSS flicker (antdv cssinjs / tailwind).
    await nextTick()
    requestAnimationFrame(() => {
      bootstrapping.value = false
    })

    // Never let an external API stall the whole UI forever.
    window.setTimeout(() => {
      siteInfoTimeoutReached.value = true
    }, 2500)
  })
}
</script>

<style scoped>
.content {
  background: transparent;
}

.layout-shell {
  transition: opacity 0.12s ease;
}

.layout-shell--pending {
  opacity: 0;
  pointer-events: none;
}

.layout-spin {
  display: block;
  min-height: 100vh;
}

.layout-spin :deep(.ant-spin-nested-loading),
.layout-spin :deep(.ant-spin-container) {
  min-height: 100vh;
}
</style>
