// App Store — installable app catalog + manifest format.
//
// This is Phase 3's "frontend scaffold, local bundles only" path: a static
// catalog of apps that ship with the build, each described by a persistable
// manifest (metadata) and resolved at runtime to a loader + icon (runtime
// bits that are NOT persisted — they're looked up from the catalog by
// manifest id on load). Installing an app = persisting its manifest id;
// uninstalling = removing it. The mechanism generalizes to remote bundles
// in Phase 4 by swapping the catalog for a fetched manifest + a
// `import(/* @vite-ignore */ entryUrl)` loader.
//
// Permissions are DECLARED on the manifest but NOT YET ENFORCED — that's
// Phase 4 (sandboxing). They're part of the contract now so a manifest
// author has to name what the app needs, and the operator can see it in
// the App Store before installing. Enforcement will land at the AppOS
// boundary (docs/mbse/components.md §9 "OS-service surface") in Phase 4.
import type { Component } from 'svelte'
import NotesIcon from '@lucide/svelte/icons/sticky-note'

// A permission an installable app can request. Maps 1:1 to entries in the
// AppOS table (docs/mbse/components.md §9). Phase 4 will enforce these at
// the store-access boundary; today they're declaration-only.
export type AppPermission =
  | 'open-window' // openAppWindow / openEntityWindow / openTaskWindow
  | 'read-context' // dashboard summary, subscribeContext
  | 'read-events' // subscribeEvents (SSE)
  | 'api:entities' // $lib/api entity endpoints
  | 'api:knowledge' // knowledge search/content
  | 'api:executions' // executions/approvals
  | 'theme' // getTheme / setTheme

// Persistable metadata describing an installable app. This is what's
// stored in localStorage when an app is installed (just the manifest id is
// persisted, actually — the manifest is re-resolved from the catalog on
// load — but the shape is the unit of interchange and will be what a
// remote `/api/v1/apps` endpoint returns in Phase 4).
export interface AppManifest {
  id: string
  title: string
  description: string
  version: string
  author?: string
  permissions: AppPermission[]
  docked?: boolean
  noIcon?: boolean
  width?: number
  height?: number
  minWidth?: number
  minHeight?: number
}

// A catalog entry: the manifest (persistable metadata) plus the runtime
// bits the catalog resolves by id — the Lucide icon component and the
// dynamic-import loader. These runtime bits are never persisted; they're
// re-looked-up from this static catalog on every load.
export interface CatalogEntry {
  manifest: AppManifest
  icon: Component
  load: () => Promise<{ default: Component }>
}

export const CATALOG: CatalogEntry[] = [
  {
    manifest: {
      id: 'notes',
      title: 'Notes',
      description: 'A scratchpad. Auto-saves to localStorage. Demo installable app.',
      version: '0.1.0',
      author: 'oikos',
      permissions: ['theme'],
      width: 640,
      height: 480,
      minWidth: 360,
      minHeight: 320
    },
    icon: NotesIcon,
    load: () => import('./apps/Notes.svelte')
  }
]

export const catalogById = new Map(CATALOG.map((e) => [e.manifest.id, e]))
