/**
 * public/launcher.ts — the home "session chooser" shown when no tab is open.
 *
 * Opening the app no longer auto-creates or auto-restores tabs. Instead this
 * start screen lists the host's running sessions as live preview thumbnails
 * (read-only xterm, same as the manage page) so the user picks which to open —
 * or starts a new one. Sessions persist server-side, so opening one replays its
 * full scrollback. The thumbnail card + preview plumbing is shared with the
 * manage page via public/preview-grid.ts (DRY).
 */

import type { LiveSessionInfo } from '../src/types.js'
import {
  el,
  relTime,
  makePreviewCard,
  updatePreviewCard,
  loadPreviewInto,
  fetchLiveSessions,
  type PreviewCard,
} from './preview-grid.js'

export interface LauncherHooks {
  onOpen: (id: string) => void
  onNew: () => void
}

const THUMB_W = 320
const THUMB_MAX_H = 200
const REFRESH_MS = 5000

export interface Launcher {
  setVisible(v: boolean): void
  refresh(): void
}

export function mountLauncher(host: HTMLElement, hooks: LauncherHooks): Launcher {
  const root = el('div', 'launcher')
  root.style.display = 'none'
  host.appendChild(root)

  const head = el('div', 'launcher-head')
  head.append(el('div', 'launcher-title', 'Your sessions'))
  const sub = el('div', 'launcher-sub', '')
  head.append(sub)
  root.append(head)

  const grid = el('div', 'mg-grid')
  root.append(grid)

  // "New session" is a tile that leads the grid (matches the session cards),
  // instead of a heavy header button. Re-prepended on every refresh.
  const newTile = el('button', 'mg-new-card')
  newTile.title = 'Start a new session'
  newTile.setAttribute('aria-label', 'New session')
  newTile.append(el('div', 'mg-new-plus', '＋'), el('div', 'mg-new-label', 'New session'))
  newTile.addEventListener('click', () => hooks.onNew())

  const cards = new Map<string, PreviewCard>()
  let timer: ReturnType<typeof setInterval> | null = null

  /** Kill a session (DELETE /live-sessions/:id) then refresh the grid. */
  async function killOne(id: string): Promise<void> {
    await fetch(`/live-sessions/${encodeURIComponent(id)}`, { method: 'DELETE' }).catch(() => {})
    void refresh()
  }

  function makeCard(s: LiveSessionInfo): PreviewCard {
    const kill = el('button', 'mg-kill', 'Kill ✕')
    kill.title = 'Kill this session'
    kill.addEventListener('click', () => void killOne(s.id))
    return makePreviewCard(s, {
      onOpen: (id) => hooks.onOpen(id),
      extraActions: () => [kill],
    })
  }

  async function refresh(): Promise<void> {
    const sessions = await fetchLiveSessions()

    sub.textContent = sessions.length
      ? `${sessions.length} running on this host — pick one to open`
      : 'No sessions running yet'

    // Keep the New-session tile as the first grid cell.
    if (grid.firstChild !== newTile) grid.prepend(newTile)

    const seen = new Set<string>()
    for (const s of sessions) {
      seen.add(s.id)
      let card = cards.get(s.id)
      if (!card) {
        card = makeCard(s)
        cards.set(s.id, card)
        grid.append(card.el)
      }
      updatePreviewCard(card, s)
      card.meta.textContent = `${s.cwd ?? 'unknown dir'} · ${s.cols}×${s.rows} · ${relTime(s.createdAt)} old`
      void loadPreviewInto(s.id, card, THUMB_W, THUMB_MAX_H)
    }
    for (const [id, card] of cards) {
      if (!seen.has(id)) {
        card.term.dispose()
        card.el.remove()
        cards.delete(id)
      }
    }

  }

  return {
    setVisible(v: boolean): void {
      root.style.display = v ? 'block' : 'none'
      if (v) {
        void refresh()
        if (timer === null) {
          timer = setInterval(() => {
            if (root.style.display !== 'none') void refresh()
          }, REFRESH_MS)
        }
      } else {
        if (timer !== null) {
          clearInterval(timer)
          timer = null
        }
        for (const card of cards.values()) card.term.dispose()
        cards.clear()
        grid.replaceChildren()
      }
    },
    refresh(): void {
      void refresh()
    },
  }
}
