import { describe, expect, it } from 'vitest'
import type { AdapterStatus } from './collector-types'
import { adapterHealthRow, healthChipLabel, healthSummary, overallHealth } from './health'
import { SIDEBAR_SECTIONS } from './sidebar-nav'

function adapter(overrides: Partial<AdapterStatus> = {}): AdapterStatus {
  return {
    id: 'harness',
    interval: 5_000,
    lastAttempt: 2_000,
    lastSuccess: 2_000,
    lastPollDurationMs: 42,
    consecutiveErrors: 0,
    stale: false,
    ...overrides,
  }
}

describe('collector health mapping', () => {
  it('keeps the health page discoverable in shell navigation', () => {
    expect(SIDEBAR_SECTIONS.flatMap((section) => section.items)).toContainEqual({ label: 'System health', href: '/health' })
  })

  it('keeps the factory page discoverable in shell navigation', () => {
    expect(SIDEBAR_SECTIONS.flatMap((section) => section.items)).toContainEqual({ label: 'Factory', href: '/factory' })
  })

  it('prioritizes errors over staleness and reports unknown without adapters', () => {
    expect(overallHealth([])).toBe('unknown')
    expect(overallHealth([adapter()])).toBe('healthy')
    expect(overallHealth([adapter({ stale: true })])).toBe('stale')
    expect(overallHealth([adapter({ stale: true }), adapter({ id: 'golive', lastError: 'down', consecutiveErrors: 2 })])).toBe('error')
  })

  it('derives reachability and gaps only from recorded adapter state', () => {
    expect(adapterHealthRow(adapter())).toMatchObject({
      id: 'harness',
      reachability: 'reachable',
      lastPollDurationMs: 42,
      consecutiveErrors: 0,
    })
    expect(adapterHealthRow(adapter({ lastSuccess: undefined, lastPollDurationMs: undefined }))).toMatchObject({
      reachability: 'unknown',
      lastSuccess: null,
      lastPollDurationMs: null,
    })
    expect(adapterHealthRow(adapter({ lastError: 'timeout', consecutiveErrors: 3 }))).toMatchObject({
      reachability: 'error',
      lastError: 'timeout',
      consecutiveErrors: 3,
    })
  })
})

describe('health chip never says only "error"', () => {
  it('names the failing adapter and its reason', () => {
    const summary = healthSummary([
      adapter(),
      adapter({ id: 'cluster', lastError: 'Executable not found in $PATH: "rtk"', consecutiveErrors: 42 }),
    ])
    expect(summary.status).toBe('error')
    expect(summary.failing).toEqual(['cluster'])
    expect(summary.detail).toContain('rtk')
    expect(healthChipLabel(summary)).toBe('error: cluster')
  })

  it('says the collector itself is unreachable rather than blaming an adapter', () => {
    const summary = healthSummary(undefined, 'fetch failed')
    expect(summary.status).toBe('error')
    expect(summary.detail).toContain('fetch failed')
    expect(healthChipLabel(summary)).toBe('error')
  })

  it('names stale adapters and counts the ones it does not list', () => {
    const summary = healthSummary([
      adapter({ id: 'a', stale: true }),
      adapter({ id: 'b', stale: true }),
      adapter({ id: 'c', stale: true }),
    ])
    expect(summary.status).toBe('stale')
    expect(healthChipLabel(summary)).toBe('stale: a, b +1')
  })

  it('reports healthy with the adapter count and no failing list', () => {
    const summary = healthSummary([adapter()])
    expect(summary.status).toBe('healthy')
    expect(summary.failing).toEqual([])
    expect(healthChipLabel(summary)).toBe('healthy')
  })

  it('says the collector has not answered yet instead of showing unknown bare', () => {
    expect(healthSummary(undefined).detail).toContain('not answered')
  })
})
