import { describe, expect, it } from 'vitest'
import { SESSIONS_PANEL_DATA, SESSION_FIXTURES } from '../../tests/fixtures/sessions-fixtures'
import { hostBreakdown } from './session-hosts'
import { toAgentSessionRow } from './session-types'

const ROWS = SESSION_FIXTURES.map(toAgentSessionRow)

const PANEL = {
  localHost: SESSIONS_PANEL_DATA.localHost,
  hosts: [
    ...SESSIONS_PANEL_DATA.hosts,
    // A registry host the ledger has never heard from — the unobserved case.
    { name: 'debian2', reachability: 'declared-enabled' as const, state: 'reachable' as const, notes: null },
  ],
  hostProbes: [
    { host: 'debian1', status: 'ok' as const, error: null, at: '2026-08-08T12:00:00.000Z', sessionCount: 1 },
    { host: 'debian2', status: 'failed' as const, error: 'ssh exit 255', at: '2026-08-08T12:00:00.000Z', sessionCount: 0 },
    { host: 'debian3', status: 'not-reachable' as const, error: 'registry state: bricked', at: '2026-08-08T12:00:00.000Z', sessionCount: 0 },
  ],
}

function row(host: string | null) {
  const found = hostBreakdown(ROWS, PANEL).find((entry) => entry.host === host)
  if (!found) throw new Error(`no breakdown row for host ${host}`)
  return found
}

describe('hostBreakdown', () => {
  it('lists every registry host, the collector host, and any host only the ledger knows', () => {
    const hosts = hostBreakdown(ROWS, PANEL).map((entry) => entry.host)
    expect(hosts).toContain('e14')
    expect(hosts).toContain('debian1')
    expect(hosts).toContain('debian2')
    expect(hosts).toContain('debian3')
  })

  it('renders observed zeros as zero and carries a failed probe reason', () => {
    const failed = row('debian2')
    expect(failed.coverage).toBe('probe-failed')
    expect(failed.probe?.error).toBe('ssh exit 255')
    expect(failed.live).toBe(0)
    expect(failed.idle).toBe(0)
    expect(failed.reconnectable).toBe(0)
    expect(failed.runningByCli).toEqual([])
    expect(failed.ledgerEntries).toBe(0)
  })

  it('separates a probe that has not returned yet from one that failed', () => {
    const pending = hostBreakdown(ROWS, {
      ...PANEL,
      hostProbes: [{ host: 'debian2', status: 'pending' as const, error: null, at: '2026-08-08T12:00:00.000Z', sessionCount: 0 }],
    })
    expect(pending.find((entry) => entry.host === 'debian2')?.coverage).toBe('probe-pending')
    expect(pending.find((entry) => entry.host === 'debian1')?.coverage).toBe('probe-pending')
    expect(pending.find((entry) => entry.host === 'e14x')).toBeUndefined()
  })

  it('keeps a real zero on the recorder host, where zero is an observation', () => {
    const single = hostBreakdown([toAgentSessionRow(SESSION_FIXTURES[0]!)], { localHost: 'nowhere', hosts: [], hostProbes: [] })
    const recorder = single.find((entry) => entry.host === 'nowhere')
    expect(recorder?.coverage).toBe('recorder')
    expect(recorder?.live).toBe(0)
    expect(recorder?.idle).toBe(0)
  })

  it('reports what a remote host did enrol, without claiming it is everything', () => {
    const debian1 = row('debian1')
    expect(debian1.coverage).toBe('probed')
    expect(debian1.live).toBe(1)
    expect(debian1.idle).toBe(0)
    expect(debian1.probe?.at).toBe('2026-08-08T12:00:00.000Z')
    expect(debian1.runningByCli).toEqual([{ cli: 'claude', count: 1 }])
  })

  it('buckets sessions the recorder stamped no host on rather than dropping them', () => {
    const unstamped = row(null)
    expect(unstamped.coverage).toBe('unstamped')
    expect(unstamped.ledgerEntries).toBeGreaterThan(0)
  })

  it('sums to the same live/idle/reconnectable totals the summary shows', () => {
    const breakdown = hostBreakdown(ROWS, PANEL)
    const total = (pick: (entry: (typeof breakdown)[number]) => number | null): number =>
      breakdown.reduce((sum, entry) => sum + (pick(entry) ?? 0), 0)
    expect(total((entry) => entry.live)).toBe(ROWS.filter((entry) => entry.state === 'live').length)
    expect(total((entry) => entry.idle)).toBe(ROWS.filter((entry) => entry.state === 'idle').length)
    expect(total((entry) => entry.reconnectable)).toBe(
      ROWS.filter((entry) => entry.attach.kind !== 'none').length,
    )
  })

  it('carries the registry verdict for a host the registry disables', () => {
    expect(row('debian3').coverage).toBe('not-reachable')
    expect(row('debian3').probe?.error).toBe('registry state: bricked')
    expect(row('debian3').facts?.state).toBe('bricked')
    expect(row('e14').facts).toBeNull()
  })
})
