<template>
  <div class="app-details-container pb-16 md:pb-16">
    <!-- Desktop Back Button -->
    <button @click="goBack" class="hidden md:flex mb-6 items-center gap-2 text-white/70 hover:text-white transition-colors">
      <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
      </svg>
      {{ backButtonText }}
    </button>

    <!-- Mobile Full-Width Back Button (teleported to escape CSS transform containing block) -->
    <Teleport to="body">
      <button
        @click="goBack"
        class="md:hidden mobile-back-btn glass-button px-6 py-3 rounded-lg font-medium shadow-2xl flex items-center justify-center gap-2"
      >
        <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
        </svg>
        <span>{{ backButtonText }}</span>
      </button>
    </Teleport>

    <div v-if="pkg">
      <AppHeroSection
        :pkg="pkg"
        :app-id="appId"
        :package-key="packageKey"
        :can-launch="canLaunch"
        :is-web-only="isWebOnly"
        @launch="launchApp"
        @start="startApp"
        @stop="stopApp"
        @restart="restartApp"
        @uninstall="uninstallApp"
        @update="updateApp"
        @channels="router.push('/dashboard/apps/lnd/channels')"
      />

      <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
        <AppContentSection
          :pkg="pkg"
          :features="features"
          :needs-bitcoin-sync="needsBitcoinSync"
          :bitcoin-synced="bitcoinSynced"
          :bitcoin-sync-percent="bitcoinSyncPercent"
          :bitcoin-block-height="bitcoinBlockHeight"
        />

        <AppSidebar
          :pkg="pkg"
          :package-key="packageKey"
          :is-web-only="isWebOnly"
          :gateway-state="gatewayState"
          :interface-addresses="interfaceAddresses"
          :lan-url="lanUrl"
          :tor-url="torUrl"
          :show-tor-address="showTorAddress"
          :credentials="credentials"
        />
      </div>
    </div>

    <!-- App Not Found -->
    <div v-else class="glass-card p-12 text-center">
      <svg class="w-24 h-24 text-white/20 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.172 16.172a4 4 0 015.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
      </svg>
      <h3 class="text-2xl font-semibold text-white mb-2">{{ t('appDetails.notFoundTitle') }}</h3>
      <p class="text-white/70">{{ t('appDetails.notFoundMessage') }}</p>
    </div>

    <!-- Uninstall Confirmation Modal -->
    <Teleport to="body">
      <Transition name="modal">
        <div
          v-if="uninstallModal.show"
          class="fixed inset-0 z-[3000] flex items-center justify-center p-4"
          @click="closeUninstallModal()"
        >
          <div class="absolute inset-0 bg-black/60 backdrop-blur-md"></div>
          <div
            ref="uninstallModalRef"
            @click.stop
            class="glass-card p-6 md:p-8 max-w-md w-full relative z-10"
          >
            <div class="flex items-start gap-4 mb-6">
              <div class="p-3 bg-red-500/20 rounded-lg flex-shrink-0">
                <svg class="w-6 h-6 text-red-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
                </svg>
              </div>
              <div class="flex-1 min-w-0">
                <h3 class="text-xl font-semibold text-white mb-2">{{ t('appDetails.uninstallTitle') }}</h3>
                <p class="text-white/70 text-sm">
                  {{ t('appDetails.uninstallConfirm', { name: uninstallModal.appTitle }) }}
                </p>
              </div>
            </div>

            <div class="flex flex-col-reverse md:flex-row gap-3 md:justify-end">
              <button
                @click="closeUninstallModal()"
                class="w-full md:w-auto px-6 py-3 glass-button rounded-lg text-sm font-medium"
              >
                {{ t('common.cancel') }}
              </button>
              <button
                @click="confirmUninstall"
                class="w-full md:w-auto px-6 py-3 glass-button glass-button-danger rounded-lg text-sm font-medium"
              >
                {{ t('common.uninstall') }}
              </button>
            </div>
          </div>
        </div>
      </Transition>
    </Teleport>

    <!-- Action error toast -->
    <Transition name="fade">
      <div v-if="actionError" class="fixed bottom-20 left-1/2 -translate-x-1/2 z-50 max-w-md w-full px-4" role="alert" aria-live="assertive">
        <div class="alert-error backdrop-blur-sm rounded-lg px-4 py-3 text-sm flex items-center justify-between gap-3">
          <span>{{ actionError }}</span>
          <button @click="actionError = ''" :aria-label="t('apps.dismissError')" class="text-red-300 hover:text-white shrink-0">&times;</button>
        </div>
      </div>
    </Transition>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { useAppStore } from '../stores/app'
import { useAppLauncherStore } from '../stores/appLauncher'
import { useModalKeyboard } from '@/composables/useModalKeyboard'
import { dummyApps } from '../utils/dummyApps'
import { rpcClient } from '@/api/rpc-client'
import type { AppCredentialsResponse } from '@/types/api'
import AppHeroSection from './appDetails/AppHeroSection.vue'
import AppContentSection from './appDetails/AppContentSection.vue'
import AppSidebar from './appDetails/AppSidebar.vue'
import { resolveAppUrl } from './appSession/appSessionConfig'
import { isWebsitePackage, resolveRuntimeLaunchUrl } from './apps/appsConfig'
import {
  WEB_ONLY_APP_URLS,
  PACKAGE_ALIASES,
  BITCOIN_DEPENDENT_APPS,
  resolvePackageKey,
  isRealOnionAddress,
} from './appDetails/appDetailsData'

const router = useRouter()
const route = useRoute()
const store = useAppStore()
const { t } = useI18n()

const appId = computed(() => {
  const id = route.params.id
  if (typeof id !== 'string' || !/^[a-z0-9][a-z0-9._-]*$/.test(id) || id.length > 64) {
    router.replace('/dashboard/apps')
    return ''
  }
  return id
})

const isWebOnly = computed(() => appId.value in WEB_ONLY_APP_URLS)

const pkg = computed(() => {
  const routeId = appId.value
  const pkgKey = resolvePackageKey(routeId)
  if (store.packages[pkgKey]) return store.packages[pkgKey]
  if (store.packages[routeId]) return store.packages[routeId]
  const aliases = PACKAGE_ALIASES[routeId]
  if (aliases) {
    for (const alias of aliases) {
      if (store.packages[alias]) return store.packages[alias]
    }
  }
  if (dummyApps[routeId]) return dummyApps[routeId]
  return null
})

const interfaceAddresses = computed(() => {
  const main = pkg.value?.installed?.['interface-addresses']?.main
  if (!main) return null
  if (!main['lan-address'] && !isRealOnionAddress(main['tor-address'])) return null
  return main
})

const lanUrl = computed(() => {
  const addr = interfaceAddresses.value?.['lan-address']
  if (!addr) return '#'
  if (addr.includes('localhost')) return addr.replace('localhost', window.location.hostname)
  return addr
})

const torUrl = computed(() => {
  const addr = interfaceAddresses.value?.['tor-address']
  if (!addr || !isRealOnionAddress(addr)) return ''
  return addr.startsWith('http') ? addr : `http://${addr}`
})

const showTorAddress = computed(() => isRealOnionAddress(interfaceAddresses.value?.['tor-address']))

const packageKey = computed(() => resolvePackageKey(appId.value))

const gatewayState = computed(() => {
  const gw = store.packages['fedimint-gateway']
  return gw ? gw.state : 'not installed'
})

const needsBitcoinSync = computed(() => BITCOIN_DEPENDENT_APPS.includes(packageKey.value))
const bitcoinSyncPercent = ref(0)
const bitcoinBlockHeight = ref(0)
const bitcoinSynced = computed(() => bitcoinSyncPercent.value >= 99.9)
const credentials = ref<AppCredentialsResponse | null>(null)

async function loadBitcoinSync() {
  if (!needsBitcoinSync.value) return
  try {
    const btc = await rpcClient.call<{ block_height: number; sync_progress: number }>({
      method: 'bitcoin.getinfo',
      timeout: 5000,
    })
    bitcoinSyncPercent.value = (btc.sync_progress ?? 0) * 100
    bitcoinBlockHeight.value = btc.block_height ?? 0
  } catch {
    bitcoinSyncPercent.value = 0
    bitcoinBlockHeight.value = 0
  }
}

async function loadCredentials() {
  if (!appId.value) return
  try {
    const result = await rpcClient.call<AppCredentialsResponse>({
      method: 'package.credentials',
      params: { app_id: packageKey.value },
      timeout: 5000,
    })
    credentials.value = result.credentials?.length ? result : null
  } catch {
    credentials.value = null
  }
}

onMounted(() => {
  loadBitcoinSync()
  loadCredentials()
})

const actionError = ref('')
let errorTimer: ReturnType<typeof setTimeout> | undefined

function showActionError(msg: string) {
  actionError.value = msg
  if (errorTimer) clearTimeout(errorTimer)
  errorTimer = setTimeout(() => { actionError.value = '' }, 5000)
}

const uninstallModal = ref({ show: false, appTitle: '' })
const uninstallModalRef = ref<HTMLElement | null>(null)
const uninstallRestoreFocusRef = ref<HTMLElement | null>(null)

function closeUninstallModal() {
  uninstallRestoreFocusRef.value?.focus?.()
  uninstallModal.value.show = false
}

useModalKeyboard(
  uninstallModalRef,
  computed(() => uninstallModal.value.show),
  closeUninstallModal,
  { restoreFocusRef: uninstallRestoreFocusRef }
)

const backButtonText = computed(() => {
  if (route.query.from === 'discover') return 'Back to Discover'
  if (route.query.from === 'marketplace') return t('appDetails.backToStore')
  return t('appDetails.backToApps')
})

const canLaunch = computed(() => {
  if (!pkg.value) return false
  if (isWebOnly.value) return true
  const hasRuntimeAddress = !!pkg.value.installed?.['interface-addresses']?.main?.['lan-address']
  const hasKnownLaunchUrl = typeof window !== 'undefined' && !!resolveAppUrl(pkg.value.manifest.id)
  const hasUI = !!(pkg.value.manifest.interfaces?.main?.ui || hasRuntimeAddress || hasKnownLaunchUrl)
  return hasUI && pkg.value.state === 'running' && pkg.value.health !== 'starting' && pkg.value.health !== 'unhealthy'
})

const features = computed(() => [
  'Self-hosted and privacy-focused',
  'Easy installation and updates',
  'Automatic backups',
  'Secure by default'
])

function goBack() {
  router.back()
}

function launchApp() {
  if (!pkg.value) return
  const id = appId.value
  const isMobile = typeof window !== 'undefined' && window.innerWidth < 768

  const webOnlyUrl = WEB_ONLY_APP_URLS[id]
  if (webOnlyUrl) {
    useAppLauncherStore().open({ url: webOnlyUrl, title: pkg.value.manifest.title, openInNewTab: !isMobile })
    return
  }

  if (isWebsitePackage(id, pkg.value)) {
    const url = resolveRuntimeLaunchUrl(pkg.value)
    if (url) {
      useAppLauncherStore().open({ url, title: pkg.value.manifest.title, openInNewTab: !isMobile })
    }
    return
  }

  const runtimeUrl = resolveRuntimeLaunchUrl(pkg.value)
  if (runtimeUrl) {
    useAppLauncherStore().open({ url: runtimeUrl, title: pkg.value.manifest.title })
    return
  }

  // Container apps should launch through session routing so protocol/path
  // handling stays centralized in appSessionConfig.
  useAppLauncherStore().openSession(id)
}


async function startApp() {
  try {
    await store.startPackage(appId.value)
  } catch (err) {
    showActionError(`Failed to start: ${err instanceof Error ? err.message : 'Unknown error'}`)
  }
}

async function stopApp() {
  try {
    await store.stopPackage(appId.value)
  } catch (err) {
    showActionError(`Failed to stop: ${err instanceof Error ? err.message : 'Unknown error'}`)
  }
}

async function restartApp() {
  try {
    await store.restartPackage(appId.value)
  } catch (err) {
    showActionError(`Failed to restart: ${err instanceof Error ? err.message : 'Unknown error'}`)
  }
}

async function updateApp() {
  try {
    await store.updatePackage(appId.value)
  } catch (err) {
    showActionError(`Failed to update: ${err instanceof Error ? err.message : 'Unknown error'}`)
  }
}

function showUninstallModal() {
  if (!pkg.value) return
  uninstallModal.value = { show: true, appTitle: pkg.value.manifest.title }
}

async function confirmUninstall() {
  uninstallModal.value.show = false
  try {
    await store.uninstallPackage(appId.value)
    router.push('/dashboard/apps').catch(() => {})
  } catch (err) {
    showActionError(`Failed to uninstall: ${err instanceof Error ? err.message : 'Unknown error'}`)
  }
}

function uninstallApp() {
  showUninstallModal()
}
</script>

<style scoped>
.modal-enter-active,
.modal-leave-active {
  transition: opacity 0.3s ease;
}

.modal-enter-active .glass-card,
.modal-leave-active .glass-card {
  transition: transform 0.3s ease, opacity 0.3s ease;
}

.modal-enter-from,
.modal-leave-to {
  opacity: 0;
}

.modal-enter-from .glass-card,
.modal-leave-to .glass-card {
  transform: scale(0.95);
  opacity: 0;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>
