/** @vitest-environment jsdom */
import { cleanup, fireEvent, render, screen, within } from '@testing-library/react'
import '@testing-library/jest-dom/vitest'
import React from 'react'
import { afterEach, describe, expect, it } from 'vitest'
import type { FactoryGateResultView } from '../../lib/factory-types'
import { FactoryDiffTable, FactoryGateTable, FactoryProcessTable } from './FactoryTraceTables'

type GateFixture = FactoryGateResultView & { violations: unknown }

function gateFixture(overrides: Partial<GateFixture> = {}): GateFixture {
  return {
    adwId: '12b0f5d2',
    phaseId: '12b0f5d2_05_verify_1',
    attempt: 1,
    gate: 'quality:test',
    passed: false,
    violations: [],
    checks: [],
    ...overrides,
  }
}

afterEach(cleanup)

describe('FactoryGateTable', () => {
  it('renders structured failing-check command metadata and the selectable command log path', () => {
    const commandLog = '/home/user/.overdeck/factory/data/sessions/12b0f5d2/context_handoff/quality/05_test/command.log'
    render(<FactoryGateTable gates={[gateFixture({
      checks: [{
        item: 'pnpm run test',
        ok: false,
        note: `exit 1; 47885ms; ${commandLog}`,
        command: 'pnpm run test',
        exit_code: 1,
        duration_ms: 47_885,
        command_log: commandLog,
      }],
    })]} />)

    const gates = screen.getByRole('table', { name: 'Factory gates' })
    fireEvent.click(within(gates).getByRole('button', { name: 'quality:test' }))
    const gateDrawer = screen.getByRole('dialog', { name: 'quality:test' })
    expect(gateDrawer).toHaveClass('w-[min(72rem,100%)]')
    const checks = within(gateDrawer).getByRole('table', { name: 'quality:test checks' })
    const gateRow = within(gates).getAllByRole('row')[1]!
    const checkRow = within(checks).getAllByRole('row')[1]!
    expect(within(gateRow).getByText('failed')).toHaveAttribute('data-status-category', 'failed')
    expect(within(checkRow).getByText('failed')).toHaveAttribute('data-status-category', 'failed')
    expect(within(gateRow).queryByText(/broken/i)).not.toBeInTheDocument()
    expect(within(checkRow).queryByText(/broken/i)).not.toBeInTheDocument()
    expect(within(checks).getAllByText('pnpm run test')).toHaveLength(2)
    expect(within(checks).getByText('1')).toBeInTheDocument()
    expect(within(checks).getByText('48s')).toBeInTheDocument()
    const path = within(checks).getByText(commandLog)
    expect(path).toBeInTheDocument()
    expect(path).toHaveClass('select-all')
  })

  it('opens the complete long failure detail in a drawer', () => {
    const sentinel = 'FINAL FAILURE SENTINEL FROM THE END OF COMMAND.LOG'
    const logTail = `${'Earlier failure output '.repeat(30)}\n${sentinel}`
    render(<FactoryGateTable gates={[gateFixture({ violations: [logTail] })]} />)

    const gates = screen.getByRole('table', { name: 'Factory gates' })
    fireEvent.click(within(gates).getByRole('button', { name: 'quality:test' }))
    const gateDrawer = screen.getByRole('dialog', { name: 'quality:test' })
    expect(within(gateDrawer).queryByText((text) => text.includes(sentinel))).not.toBeInTheDocument()
    const label = within(gateDrawer).getByText('Failure detail')
    fireEvent.click(within(label.parentElement!).getByRole('button', { name: 'Read more' }))

    const detailDrawer = screen.getByRole('dialog', { name: 'Failure detail' })
    expect(within(detailDrawer).getByText((_, element) => (
      element?.tagName === 'PRE' && element.textContent?.includes(sentinel) === true
    ))).toBeInTheDocument()
  })

  it('keeps a passing gate on the existing checks-only presentation', () => {
    render(<FactoryGateTable gates={[gateFixture({
      passed: true,
      violations: ['must not render'],
      checks: [{ item: 'pnpm run test', ok: true, command: 'pnpm run test', returncode: 0 }],
    })]} />)

    const gates = screen.getByRole('table', { name: 'Factory gates' })
    const gateRow = within(gates).getAllByRole('row')[1]!
    expect(within(gateRow).getByText('passed')).toHaveAttribute('data-status-category', 'completed')
    fireEvent.click(within(gateRow).getByRole('button', { name: 'quality:test' }))
    const gateDrawer = screen.getByRole('dialog', { name: 'quality:test' })
    const checks = within(gateDrawer).getByRole('table', { name: 'quality:test checks' })
    const checkRow = within(checks).getAllByRole('row')[1]!
    expect(within(checkRow).getByText('passed')).toHaveAttribute('data-status-category', 'completed')
    expect(checks).toBeInTheDocument()
    expect(within(checks).getByRole('columnheader', { name: 'Return code' })).toBeInTheDocument()
    expect(within(checks).queryByRole('columnheader', { name: 'Duration' })).not.toBeInTheDocument()
    expect(within(checks).queryByRole('columnheader', { name: 'Command log' })).not.toBeInTheDocument()
    expect(within(gateDrawer).getByText('Raw gate result')).toBeInTheDocument()
    expect(within(gateDrawer).queryByText('Failure detail')).not.toBeInTheDocument()
    expect(within(gateDrawer).queryByText('must not render')).not.toBeInTheDocument()
  })

  it('states explicitly when a failed gate has no violation details', () => {
    render(<FactoryGateTable gates={[gateFixture({ violations: [] })]} />)

    const gates = screen.getByRole('table', { name: 'Factory gates' })
    fireEvent.click(within(gates).getByRole('button', { name: 'quality:test' }))
    const gateDrawer = screen.getByRole('dialog', { name: 'quality:test' })
    expect(within(gateDrawer).getByText('No failure details were recorded for this failed gate.')).toBeInTheDocument()
  })

  it('renders unknown gate and check verdicts honestly', () => {
    render(<FactoryGateTable gates={[gateFixture({
      passed: null,
      checks: [{ item: 'pending check' }],
    })]} />)

    const gates = screen.getByRole('table', { name: 'Factory gates' })
    const gateRow = within(gates).getAllByRole('row')[1]!
    expect(within(gateRow).getByText('unknown')).toHaveAttribute('data-status-category', 'unknown')
    fireEvent.click(within(gateRow).getByRole('button', { name: 'quality:test' }))
    const gateDrawer = screen.getByRole('dialog', { name: 'quality:test' })
    const checks = within(gateDrawer).getByRole('table', { name: 'quality:test checks' })
    const checkRow = within(checks).getAllByRole('row')[1]!
    expect(within(checkRow).getByText('unknown')).toHaveAttribute('data-status-category', 'unknown')
  })
})

describe('FactoryDiffTable', () => {
  it('opens the full diff text and changed-file list for a phase', () => {
    render(<FactoryDiffTable diffs={[{
      phaseId: '106f93ee_04_build',
      attempt: 1,
      files: [
        { path: 'modules/workstation/claude/bin/wt-reaper.sh', status: 'M', insertions: 5, deletions: 7 },
        { path: 'modules/workstation/claude/hooks/bash-gate.sh', status: 'M', insertions: 11, deletions: 13 },
      ],
      insertions: 16,
      deletions: 20,
      diffText: 'diff --git a/bin/wt-reaper.sh b/bin/wt-reaper.sh\n-runplan\n',
      truncated: false,
      createdAt: '2026-08-09T10:00:00Z',
    }]} />)

    const table = screen.getByRole('table', { name: 'Factory phase diffs' })
    const row = within(table).getAllByRole('row')[1]!
    expect(within(row).getByText('+16')).toBeInTheDocument()
    expect(within(row).getByText('−20')).toBeInTheDocument()
    expect(within(row).getByText('full')).toHaveAttribute('data-status-category', 'completed')

    fireEvent.click(within(table).getByRole('button', { name: '106f93ee_04_build' }))
    const drawer = screen.getByRole('dialog', { name: 'Phase diff' })
    const files = within(drawer).getByRole('table', { name: 'Changed files' })
    expect(within(files).getByText('modules/workstation/claude/hooks/bash-gate.sh')).toHaveClass('select-all')
    expect(within(files).getByText('+11')).toBeInTheDocument()
    fireEvent.click(within(drawer).getByRole('button', { name: 'Read more' }))
    expect(screen.getByRole('dialog', { name: 'Diff' })).toHaveTextContent('-runplan')
  })

  it('marks a truncated diff and says so when no diff text was recorded', () => {
    render(<FactoryDiffTable diffs={[{
      phaseId: 'p1', attempt: null, files: [], insertions: null, deletions: null,
      diffText: null, truncated: true, createdAt: null,
    }]} />)

    const table = screen.getByRole('table', { name: 'Factory phase diffs' })
    expect(within(table).getByText('truncated')).toHaveAttribute('data-status-category', 'failed')
    fireEvent.click(within(table).getByRole('button', { name: 'p1' }))
    expect(screen.getByText('No diff text was recorded for this phase.')).toBeInTheDocument()
  })
})

describe('FactoryProcessTable', () => {
  it('shows each owned process with its pid, command and liveness', () => {
    render(<FactoryProcessTable processes={[
      {
        kind: 'adw', name: '', pid: 4242, command: 'factory adw_build spec.md',
        startedAt: '2026-08-09T10:00:00Z', endedAt: '2026-08-09T10:03:00Z', durationMs: 180_000,
      },
      {
        kind: 'agent', name: 'coder', pid: 4243, command: 'cursor-agent',
        startedAt: '2026-08-09T10:00:10Z', endedAt: null, durationMs: null,
      },
    ]} />)

    const table = screen.getByRole('table', { name: 'Factory processes' })
    const first = within(table).getAllByRole('row')[1]!
    expect(within(first).getByText('4242')).toBeInTheDocument()
    expect(within(first).getByText('factory adw_build spec.md')).toHaveClass('select-all')
    expect(within(first).getByText('exited')).toHaveAttribute('data-status-category', 'completed')
    const second = within(table).getAllByRole('row')[2]!
    expect(within(second).getByText('alive')).toHaveAttribute('data-status-category', 'running')
  })
})
