<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from 'vue'

type InstallMode = 'native' | 'ios' | 'android-menu' | 'desktop' | 'https-required'

const showInstall = ref(false)
const dismissed = ref(false)
const installMode = ref<InstallMode | null>(null)
const isMobile = ref(false)
let deferredPrompt: BeforeInstallPromptEvent | null = null
let fallbackTimer: ReturnType<typeof setTimeout> | null = null

interface BeforeInstallPromptEvent extends Event {
  prompt: () => Promise<void>
  userChoice: Promise<{ outcome: 'accepted' | 'dismissed' }>
}

const visible = computed(() => !dismissed.value && showInstall.value && installMode.value !== null)

function needsHttpsForInstall() {
  return (
    !window.isSecureContext &&
    !['localhost', '127.0.0.1'].includes(location.hostname)
  )
}

function onBeforeInstallPrompt(event: Event) {
  event.preventDefault()
  deferredPrompt = event as BeforeInstallPromptEvent
  installMode.value = 'native'
  showInstall.value = true
  if (fallbackTimer) {
    clearTimeout(fallbackTimer)
    fallbackTimer = null
  }
}

onMounted(() => {
  isMobile.value = window.matchMedia('(max-width: 767px)').matches

  if (sessionStorage.getItem('install-app-dismissed') === '1') {
    dismissed.value = true
    return
  }

  const isStandalone =
    window.matchMedia('(display-mode: standalone)').matches ||
    (window.navigator as Navigator & { standalone?: boolean }).standalone

  if (isStandalone) return

  const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent)
  if (isIOS) {
    installMode.value = 'ios'
    showInstall.value = true
    return
  }

  if (needsHttpsForInstall()) {
    installMode.value = 'https-required'
    showInstall.value = true
    return
  }

  window.addEventListener('beforeinstallprompt', onBeforeInstallPrompt)

  fallbackTimer = setTimeout(() => {
    if (deferredPrompt || installMode.value) return
    installMode.value = isMobile.value ? 'android-menu' : 'desktop'
    showInstall.value = true
  }, 2500)
})

onUnmounted(() => {
  window.removeEventListener('beforeinstallprompt', onBeforeInstallPrompt)
  if (fallbackTimer) clearTimeout(fallbackTimer)
})

async function installApp() {
  if (!deferredPrompt) return
  await deferredPrompt.prompt()
  await deferredPrompt.userChoice
  deferredPrompt = null
  showInstall.value = false
}

function dismiss() {
  dismissed.value = true
  sessionStorage.setItem('install-app-dismissed', '1')
}
</script>

<template>
  <div v-if="visible" class="install-app">
    <div class="install-app__content">
      <p v-if="installMode === 'native'" class="install-app__text">
        可将「道德经」安装到桌面，像 App 一样使用。
      </p>
      <p v-else-if="installMode === 'ios'" class="install-app__text">
        iPhone：Safari 底部分享 →「添加到主屏幕」，阅读更方便。
      </p>
      <p v-else-if="installMode === 'android-menu'" class="install-app__text">
        Android：Chrome 右上角菜单 →「安装应用」或「添加到主屏幕」。
      </p>
      <p v-else-if="installMode === 'desktop'" class="install-app__text">
        电脑：地址栏右侧点击「安装」图标，或浏览器菜单 →「安装道德经」。
      </p>
      <p v-else class="install-app__text">
        安装应用需通过 HTTPS 域名访问（内网 http://IP 地址只能添加快捷方式，无法真正安装）。
      </p>
      <div class="install-app__actions">
        <button
          v-if="installMode === 'native'"
          type="button"
          class="install-app__primary"
          @click="installApp"
        >
          安装应用
        </button>
        <button type="button" class="install-app__ghost" @click="dismiss">知道了</button>
      </div>
    </div>
  </div>
</template>

<style scoped>
.install-app {
  position: fixed;
  right: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom, 0));
  z-index: 50;
  max-width: min(92vw, 360px);
}

.install-app__content {
  padding: 14px 16px;
  border-radius: 12px;
  border: 1px solid var(--vp-c-divider);
  background: var(--vp-c-bg-soft);
  box-shadow: var(--vp-shadow-3);
}

.install-app__text {
  margin: 0 0 12px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--vp-c-text-1);
}

.install-app__actions {
  display: flex;
  gap: 8px;
}

.install-app__primary,
.install-app__ghost {
  border-radius: 8px;
  padding: 10px 14px;
  font-size: 14px;
  cursor: pointer;
}

.install-app__primary {
  border: none;
  background: var(--vp-c-brand-1);
  color: var(--vp-c-bg);
}

.install-app__ghost {
  border: 1px solid var(--vp-c-divider);
  background: transparent;
  color: var(--vp-c-text-2);
}

@media (max-width: 767px) {
  .install-app {
    left: 12px;
    right: 12px;
    max-width: none;
  }
}
</style>
