<script lang="ts">
  // The floating-window layer — mounted once inside Desktop.svelte, above the
  // icons layer, so every window (an app, a task, an entity detail) shares
  // one stack instead of each page owning its own single-entity
  // sidebar/sheet. See $lib/stores/windows.ts. Content is resolved purely
  // from the window's id, which is why persisted/hydrated windows (see
  // wmPersist in windows.ts) need no extra bookkeeping to know what to render:
  //   app:<id>      -> registry component (windows.ts openAppWindow)
  //   session:<id>  -> SessionChatWindow (windows.ts openTaskWindow)
  //   new-task      -> NewTaskChat (windows.ts openNewTaskWindow)
  //   anything else -> entity slug -> EntityDetailContent
  import {
    wm,
    dk,
    wmState,
    windowKeys,
    openEntityWindow,
    NEW_TASK_WINDOW_ID,
    SESSION_PREFIX,
    takePendingTaskDraft
  } from '$lib/stores/windows'
  import { appById, appIdFromWindowId } from '$lib/apps'
  import EntityDetailContent from '../EntityDetailContent.svelte'
  import SessionChatWindow from '../SessionChatWindow.svelte'
  import NewTaskChat from './NewTaskChat.svelte'
  import LazyApp from '$lib/components/desktop-shell/LazyApp.svelte'
  import XIcon from '@lucide/svelte/icons/x'
  import MinusIcon from '@lucide/svelte/icons/minus'
  import Maximize2Icon from '@lucide/svelte/icons/maximize-2'

  // A hydrated `app:<id>` window whose id no longer matches any registry
  // entry (the app was uninstalled/removed since the layout was persisted)
  // has nothing to render — close it rather than leaving a permanently-blank
  // window stuck in the taskbar. Reactive on `appById` so reinstalling an
  // app revives its persisted window on the next tick rather than requiring
  // a reload, and uninstalling closes its orphan window immediately.
  $effect(() => {
    const idx = $appById
    for (const id of $wmState.order) {
      const appId = appIdFromWindowId(id)
      if (appId && !idx.has(appId)) wm.close(id)
    }
  })

  // Keep an open app window's title in sync with its registry entry. The
  // title is copied into the window at open time and then persisted, so a
  // rename (e.g. "Knowledge Base" -> "Fleet") would otherwise stay stuck in
  // the titlebar/taskbar of any already-open or hydrated window until it was
  // closed and reopened. Mirrors the task-window title sync in windows.ts.
  $effect(() => {
    const idx = $appById
    for (const id of $wmState.order) {
      const appId = appIdFromWindowId(id)
      const app = appId ? idx.get(appId) : undefined
      if (app && $wmState.windows[id]?.title !== app.title) {
        wm.update(id, { title: app.title })
      }
    }
  })
</script>

<div use:dk.desktop class="absolute inset-0 z-40 pointer-events-none">
  {#each $windowKeys as id (id)}
    {@const win = $wmState.windows[id]}
    {@const appId = appIdFromWindowId(id)}
    {@const app = appId ? $appById.get(appId) : undefined}
    {#if win && (!appId || app)}
      <section use:dk.window={{ id }} class="min-w-0" aria-label={win.title}>
        <header
          data-wm-drag
          class="flex h-9 shrink-0 cursor-move items-center justify-between gap-2 overflow-hidden border-b border-border bg-background px-3"
        >
          <span
            data-wm-title
            class="min-w-0 flex-1 truncate font-mono text-xs font-medium"
            >{win.title}</span
          >
          <div class="flex shrink-0 items-center gap-1">
            <button
              type="button"
              data-wm-minimize
              class="win-ctrl flex size-6"
              aria-label="Minimize {win.title}"
            >
              <MinusIcon class="size-3.5" />
            </button>
            <button
              type="button"
              data-wm-maximize
              class="win-ctrl flex size-6"
              aria-label="Maximize {win.title}"
            >
              <Maximize2Icon class="size-3.5" />
            </button>
            <button
              type="button"
              data-wm-close
              class="win-ctrl flex size-6"
              aria-label="Close {win.title}"
            >
              <XIcon class="size-3.5" />
            </button>
          </div>
        </header>
        <div data-wm-content class="min-h-0 flex-1 overflow-hidden">
          {#key id}
            {#if id.startsWith(SESSION_PREFIX)}
              <SessionChatWindow sessionId={id.slice(SESSION_PREFIX.length)} />
            {:else if id === NEW_TASK_WINDOW_ID}
              <NewTaskChat initialDraft={takePendingTaskDraft()} />
            {:else if app}
              <LazyApp load={app.component} />
            {:else}
              <EntityDetailContent slug={id} onSelectEntity={openEntityWindow} />
            {/if}
          {/key}
        </div>
      </section>
    {/if}
  {/each}
</div>
