/**
 * public/manage.ts — standalone Session Manager page (/manage.html).
 *
 * A full-page grid of the host's running sessions, each with a LIVE preview
 * thumbnail (a read-only xterm rendering the session's current screen, scaled
 * down like a screenshot) so you can see what each one is doing at a glance.
 * Open one (?join=<id>), kill one, or bulk-kill. Auto-refreshes.
 *
 * Previews use GET /live-sessions/:id/preview (the scrollback tail) — they do
 * NOT open a WS / attach, so they don't inflate watcher counts or keep sessions
 * alive. The card + preview plumbing is shared with the launcher via
 * public/preview-grid.ts (DRY).
 */

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

const REFRESH_MS = 4000
const THUMB_W = 360 // card thumbnail width in px
const THUMB_MAX_H = 220

const cards = new Map<string, PreviewCard>()
let busy = false

async function killOne(id: string): Promise<void> {
  await fetch(`/live-sessions/${id}`, { method: 'DELETE' }).catch(() => {})
  void render()
}

async function killBulk(detachedOnly: boolean): Promise<void> {
  const label = detachedOnly ? 'all DETACHED sessions (no device watching)' : 'ALL sessions'
  if (!confirm(`Kill ${label}? Running shells/Claude will be terminated.`)) return
  await fetch(`/live-sessions${detachedOnly ? '?detached=1' : ''}`, { method: 'DELETE' }).catch(() => {})
  void render()
}

function makeCard(s: LiveSessionInfo): PreviewCard {
  const kill = el('button', 'mg-kill', 'Kill ✕')
  kill.addEventListener('click', () => void killOne(s.id))
  return makePreviewCard(s, {
    onOpen: (id) => {
      location.href = `/?join=${id}`
    },
    openHref: (id) => `/?join=${id}`,
    extraActions: () => [kill],
  })
}

function updateCard(card: PreviewCard, s: LiveSessionInfo): void {
  updatePreviewCard(card, s)
  card.meta.textContent = `${s.cwd ?? 'unknown dir'} · ${s.cols}×${s.rows} · ${relTime(s.createdAt)} old · ${s.id.slice(0, 8)}`
}

const root = document.getElementById('manage-root')
if (!root) throw new Error('#manage-root not found')

let grid: HTMLElement | null = null
let countEl: HTMLElement | null = null

function ensureChrome(): void {
  if (grid) return
  const header = el('div', 'mg-header')
  header.append(el('div', 'mg-title', 'Session Manager'))
  countEl = el('div', 'mg-sub', '')
  header.append(countEl)

  const bar = el('div', 'mg-bar')
  const back = el('a', 'mg-btn', '← Back to terminal') as HTMLAnchorElement
  back.href = '/'
  const refresh = el('button', 'mg-btn', '↻ Refresh')
  refresh.addEventListener('click', () => void render())
  const killDetached = el('button', 'mg-btn warn', 'Kill detached')
  killDetached.addEventListener('click', () => void killBulk(true))
  const killAll = el('button', 'mg-btn danger', 'Kill all')
  killAll.addEventListener('click', () => void killBulk(false))
  bar.append(back, refresh, killDetached, killAll)
  header.append(bar)

  grid = el('div', 'mg-grid')
  root!.append(header, grid)
}

async function render(): Promise<void> {
  if (busy) return
  busy = true
  ensureChrome()

  const sessions = await fetchLiveSessions()
  if (countEl) countEl.textContent = `${sessions.length} session(s) running on the host`

  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)
    }
    updateCard(card, s)
    void loadPreviewInto(s.id, card, THUMB_W, THUMB_MAX_H)
  }
  // Drop cards for sessions that are gone.
  for (const [id, card] of cards) {
    if (!seen.has(id)) {
      card.term.dispose()
      card.el.remove()
      cards.delete(id)
    }
  }

  if (sessions.length === 0 && grid && grid.querySelector('.mg-empty') === null) {
    grid.append(el('div', 'mg-empty', 'No sessions running. Open the terminal to start one.'))
  } else {
    grid?.querySelector('.mg-empty')?.remove()
  }
  busy = false
}

void render()
setInterval(() => void render(), REFRESH_MS)
// Re-scale thumbnails if the window resizes.
window.addEventListener('resize', () => {
  for (const card of cards.values()) fitThumb(card, THUMB_W, THUMB_MAX_H)
})
