/**
 * T9 (v0.10) — grid of `preview-client` cards (the manage-page moved CLIENT-SIDE under E2E).
 *
 * Renders one read-only, locally-decrypted preview per authorized host. A host the account can't
 * reach → `loadReplay` rejects → the card shows "unavailable", never another tenant's screen
 * (INV1). Disposes all preview clients on unmount so no xterms/sockets leak (EXPLORE §6 preview-cost
 * discipline); `hostContentSecret` is never written to `localStorage`/`console`.
 */
import type { ApiClient } from './api-client'
import type { HostRecord } from './api-schemas'
import {
  mountPreviewClient,
  type PreviewClient,
  type PreviewDeps,
  type ReplaySource,
} from './preview-client'

const DEFAULT_DIMS = { cols: 80, rows: 24 } as const

export interface PreviewGridOpts {
  readonly dims?: { cols: number; rows: number }
}

export function mountPreviewGrid(
  root: HTMLElement,
  api: ApiClient,
  loadReplay: (
    hostId: string,
  ) => Promise<{ replay: ReplaySource; hostContentSecret: Uint8Array }>,
  deps: PreviewDeps,
  opts: PreviewGridOpts = {},
): { dispose(): void } {
  const dims = opts.dims ?? DEFAULT_DIMS
  const clients: PreviewClient[] = []
  let disposed = false

  function unavailableCard(host: HostRecord): HTMLElement {
    const card = document.createElement('div')
    card.className = 'preview-card'
    card.dataset['hostId'] = host.hostId
    const msg = document.createElement('p')
    msg.className = 'preview-unavailable'
    msg.textContent = 'unavailable'
    card.append(msg)
    return card
  }

  async function build(): Promise<void> {
    let hosts: readonly HostRecord[]
    try {
      hosts = await api.listHosts()
    } catch {
      const err = document.createElement('p')
      err.className = 'preview-grid-error'
      err.textContent = 'Could not load previews.'
      root.append(err)
      return
    }
    if (disposed) return

    for (const host of hosts) {
      const card = document.createElement('div')
      card.className = 'preview-card'
      card.dataset['hostId'] = host.hostId
      root.append(card)
      try {
        const { replay, hostContentSecret } = await loadReplay(host.hostId)
        if (disposed) return
        const client = mountPreviewClient(card, replay, hostContentSecret, dims, deps)
        clients.push(client)
        await client.render()
      } catch {
        // A host the account can't reach (403) or a decrypt failure → "unavailable" (INV1).
        card.replaceWith(unavailableCard(host))
      }
    }
  }

  void build()

  return {
    dispose(): void {
      disposed = true
      for (const c of clients) c.dispose() // no leaked xterms/sockets
    },
  }
}
