import { render, screen } from '@testing-library/react'
import { describe, expect, it } from 'vitest'
import { FLEET_CONFIG_DRIFTED, FLEET_DEBIAN1, FLEET_DEBIAN2_JOINING, FLEET_LAPTOP } from './fixtures/offload'
import { MachineCard } from './MachineCard'

describe('MachineCard', () => {
  it('renders host name, load, and capability probes', () => {
    render(
      <MachineCard
        machine={FLEET_DEBIAN1}
        warn
        statusPill="dispatch wedged"
        statusPillIntent="warn"
        actions={[{ label: 'Reconcile', verb: 'admission-reconcile', primary: true }]}
      />,
    )
    expect(screen.getByTestId('machine-card-debian1')).toBeInTheDocument()
    // 3 ledger-tracked + 4 seats + 1 offload shell: the ledger never recorded the seats.
    expect(screen.getByTestId('machine-stat-sessions')).toHaveTextContent('8')
    expect(screen.getByTestId('machine-stat-running')).toHaveTextContent('7')
    expect(screen.getByText(/3\.9 \/ 8/)).toBeInTheDocument()
    expect(screen.getAllByText(/playwright browsers/).length).toBeGreaterThan(0)
    expect(screen.getByRole('button', { name: 'Reconcile' })).toHaveAttribute('data-action-verb', 'admission-reconcile')
  })

  it('renders enrolling state for a joining host', () => {
    render(
      <MachineCard
        machine={FLEET_DEBIAN2_JOINING}
        statusPill="enrolling"
        actions={[{ label: 'Enroll', verb: 'box-restore', primary: true }]}
      />,
    )
    expect(screen.getByText('— · enrolling')).toBeInTheDocument()
    expect(screen.getByText('capability probe pending')).toBeInTheDocument()
    expect(screen.getByTestId('machine-stat-sessions')).toHaveTextContent('n/a')
    expect(screen.getByTestId('machine-stat-slots')).toHaveTextContent('n/a')
  })

  it('counts every placement path in running, not just controller-placed jobs', () => {
    render(
      <MachineCard
        machine={{
          ...FLEET_DEBIAN1,
          running: 0,
          remoteWork: { agentSeats: 2, remoteBuildJobs: 1, offloadShells: 1 },
        }}
        actions={[]}
      />,
    )
    const running = screen.getByTestId('machine-stat-running')
    expect(running).toHaveTextContent('4')
    expect(running).not.toHaveAttribute('data-unobserved')
    expect(running).toHaveAttribute('data-tipb', expect.stringContaining('2 agent seats'))
    expect(running).toHaveAttribute('data-tipb', expect.stringContaining('1 remote build'))
    expect(running).toHaveAttribute('data-tipb', expect.stringContaining('1 offload shell'))
  })

  it('adds seats the session ledger never recorded to the sessions count', () => {
    render(
      <MachineCard
        machine={{
          ...FLEET_DEBIAN1,
          sessions: 0,
          remoteWork: { agentSeats: 3, remoteBuildJobs: 5, offloadShells: 1 },
        }}
        actions={[]}
      />,
    )
    expect(screen.getByTestId('machine-stat-sessions')).toHaveTextContent('4')
  })

  it('marks an unpublished work count unobserved rather than rendering it as zero', () => {
    render(<MachineCard machine={{ ...FLEET_DEBIAN1, remoteWork: null }} actions={[]} />)
    const running = screen.getByTestId('machine-stat-running')
    expect(running).toHaveTextContent('n/a')
    expect(running).not.toHaveTextContent('0')
    expect(running).toHaveAttribute('data-unobserved', 'true')
    expect(running).toHaveAttribute('data-tipb', expect.stringContaining('published no work count'))
  })

  it('reports a sessions count missing one of its two sources as a floor', () => {
    render(
      <MachineCard
        machine={{
          ...FLEET_DEBIAN1,
          sessions: null,
          remoteWork: { agentSeats: 2, remoteBuildJobs: 0, offloadShells: 0 },
        }}
        actions={[]}
      />,
    )
    const sessions = screen.getByTestId('machine-stat-sessions')
    expect(sessions).toHaveTextContent('≥2')
    expect(sessions).toHaveAttribute('data-tipb', expect.stringContaining('ledger count not published'))
  })

  it('says a host has no 24-hour history instead of showing a bare dash', () => {
    render(<MachineCard machine={{ ...FLEET_DEBIAN1, builds24h: null }} actions={[]} />)
    const builds = screen.getByTestId('machine-stat-24h')
    expect(builds).toHaveTextContent('n/a')
    expect(builds).toHaveAttribute('data-tipb', expect.stringContaining('no 24-hour build history'))
  })

  it('states why a red capability probe is red, in the chip tooltip and inline', () => {
    render(
      <MachineCard
        machine={{
          ...FLEET_DEBIAN2_JOINING,
          capability: {
            probes: [{
              name: 'capability',
              ok: false,
              detail: 'ssh debian3:2222 exited 255 (ssh transport, auth, or host-key failure)',
              checkedAt: '2026-08-08T03:00:00.000Z',
            }],
          },
        }}
        actions={[]}
      />,
    )
    expect(
      screen.getByText(
        'capability: ssh debian3:2222 exited 255 (ssh transport, auth, or host-key failure)',
      ),
    ).toBeInTheDocument()
    expect(screen.getByText('capability')).toHaveAttribute(
      'data-tipb',
      'capability: ssh debian3:2222 exited 255 (ssh transport, auth, or host-key failure)',
    )
  })

  it('names the telemetry gap instead of a bare dash when a host reports no load', () => {
    render(
      <MachineCard
        machine={{
          ...FLEET_DEBIAN2_JOINING,
          load: null,
          capability: {
            probes: [{
              name: 'telemetry',
              ok: false,
              detail: 'telemetry is 600s old (max 90s)',
            }],
          },
        }}
        actions={[]}
      />,
    )
    expect(screen.getByText('— · telemetry is 600s old (max 90s)')).toBeInTheDocument()
  })

  it('shows a real load for a host still enrolling rather than suppressing it', () => {
    render(
      <MachineCard
        machine={{ ...FLEET_DEBIAN2_JOINING, load: 0.8, cores: 8 }}
        actions={[]}
      />,
    )
    expect(screen.getByText(/0\.8 \/ 8/)).toBeInTheDocument()
  })

  it('marks workstation spill state', () => {
    render(
      <MachineCard
        machine={FLEET_LAPTOP}
        warn
        statusPill="spill on · stale"
        statusPillIntent="warn"
        actions={[{ label: 'Recall spill', verb: 'recall-spill', primary: true }]}
      />,
    )
    expect(screen.getByText('16.0 / 16 · saturated')).toBeInTheDocument()
    expect(screen.getByText('workstation')).toBeInTheDocument()
  })

  it('shows the config parity verdict with the time it was probed', () => {
    const probedMs = Date.parse(FLEET_CONFIG_DRIFTED.parity!.probedAt)
    render(<MachineCard machine={FLEET_CONFIG_DRIFTED} actions={[]} nowMs={probedMs + 11 * 60_000} />)
    const row = screen.getByTestId('machine-parity-debian3')
    expect(row).toHaveTextContent('drifted')
    expect(row).toHaveTextContent('11m ago')
    expect(row).toHaveAttribute('data-tipb', FLEET_CONFIG_DRIFTED.parity!.detail)
  })

  // A host the timer has not probed must not inherit the fleet's verdict.
  it('says so when no parity verdict was recorded', () => {
    render(<MachineCard machine={FLEET_DEBIAN2_JOINING} actions={[]} />)
    expect(screen.getByTestId('machine-parity-debian2')).toHaveTextContent('— not probed')
  })
})
