<template>
  <div class="app-icon-grid-wrap">
    <!-- Swipeable pages -->
    <div
      ref="scrollContainer"
      class="app-icon-pages"
      @scroll="onScroll"
    >
      <div
        v-for="(page, pageIndex) in pages"
        :key="pageIndex"
        class="app-icon-page"
      >
        <div
          v-for="([id, pkg]) in page"
          :key="id"
          class="app-icon-item"
          role="button"
          :tabindex="0"
          :aria-label="getTitle(id, pkg)"
          @click="handleTap(id, pkg)"
          @keydown.enter="handleTap(id, pkg)"
        >
          <!-- Icon with status indicator -->
          <div class="app-icon-frame">
            <img
              :src="getIcon(id, pkg)"
              :alt="getTitle(id, pkg)"
              class="app-icon-img"
              @error="handleImageError"
            />
            <!-- Status dot -->
            <span
              v-if="pkg.state === 'running'"
              class="app-icon-status app-icon-status-running"
            ></span>
            <span
              v-else-if="pkg.state === 'exited'"
              class="app-icon-status app-icon-status-error"
            ></span>
            <span
              v-else-if="pkg.state === 'starting' || pkg.state === 'stopping' || pkg.state === 'installing'"
              class="app-icon-status app-icon-status-transition"
            ></span>
            <!-- Installing overlay -->
            <div
              v-if="serverStore.isInstalling(id)"
              class="app-icon-installing"
            >
              <svg class="animate-spin h-5 w-5 text-white" fill="none" viewBox="0 0 24 24">
                <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
                <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
              </svg>
            </div>
          </div>
          <!-- Label -->
          <span class="app-icon-label">{{ getTitle(id, pkg) }}</span>
        </div>
      </div>
    </div>

    <!-- Page dots -->
    <div v-if="pages.length > 1" class="app-icon-dots">
      <button
        v-for="(_, i) in pages"
        :key="i"
        class="app-icon-dot"
        :class="{ 'app-icon-dot-active': i === activePage }"
        :aria-label="`Page ${i + 1}`"
        @click="scrollToPage(i)"
      ></button>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import { useServerStore } from '@/stores/server'
import { useAppLauncherStore } from '@/stores/appLauncher'
import type { PackageDataEntry } from '@/types/api'
import { canLaunch, handleImageError } from './appsConfig'
import { getCuratedAppList } from '../discover/curatedApps'

const ITEMS_PER_PAGE = 16 // 4 columns x 4 rows

const serverStore = useServerStore()
const appLauncher = useAppLauncherStore()

const curatedMap = new Map(getCuratedAppList().map(a => [a.id, a]))

const props = defineProps<{
  apps: [string, PackageDataEntry][]
}>()

const emit = defineEmits<{
  goToApp: [id: string]
}>()

const scrollContainer = ref<HTMLElement | null>(null)
const activePage = ref(0)

const pages = computed(() => {
  const result: [string, PackageDataEntry][][] = []
  for (let i = 0; i < props.apps.length; i += ITEMS_PER_PAGE) {
    result.push(props.apps.slice(i, i + ITEMS_PER_PAGE))
  }
  return result.length ? result : [[]]
})

function getTitle(id: string, pkg: PackageDataEntry): string {
  const t = pkg.manifest?.title
  if (t && t !== id) return t
  return curatedMap.get(id)?.title || t || id
}

function getIcon(id: string, pkg: PackageDataEntry): string {
  const i = pkg['static-files']?.icon
  return i || curatedMap.get(id)?.icon || `/assets/img/app-icons/${id}.png`
}

function handleTap(id: string, pkg: PackageDataEntry) {
  if (canLaunch(pkg)) {
    appLauncher.openSession(id)
  } else {
    emit('goToApp', id)
  }
}

function onScroll() {
  const el = scrollContainer.value
  if (!el) return
  const pageWidth = el.clientWidth
  if (pageWidth === 0) return
  activePage.value = Math.round(el.scrollLeft / pageWidth)
}

function scrollToPage(index: number) {
  const el = scrollContainer.value
  if (!el) return
  el.scrollTo({ left: index * el.clientWidth, behavior: 'smooth' })
}
</script>
