/** @vitest-environment jsdom */
import { cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react'
import '@testing-library/jest-dom/vitest'
import React from 'react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import type { RequestRow } from '../../lib/request-types'
import { RequestsBoard } from './RequestsBoard'

afterEach(() => cleanup())

function row(overrides: Partial<RequestRow>): RequestRow {
  return {
    id: 'req-a',
    title: 'Title',
    project: 'Overdeck',
    state: 'asked',
    priority: 'NORMAL',
    origin: 'owner',
    asked_at: '2026-08-14T00:00:00.000Z',
    updated_at: '2026-08-14T00:00:00.000Z',
    worker: null,
    detail: null,
    proof_url: null,
    plan_ref: null,
    ...overrides,
  }
}

describe('RequestsBoard lifecycle view', () => {
  it('maps every recorded lifecycle state to its owner-facing column', () => {
    render(<RequestsBoard requests={[
      row({ id: 'asked', title: 'Asked one', state: 'asked' }),
      row({ id: 'flying', title: 'Flying one', state: 'in_flight' }),
      row({ id: 'blocked', title: 'Blocked one', state: 'blocked_needs_owner' }),
      row({ id: 'recovery', title: 'Recovery one', state: 'orphaned', detail: 'Worker session stopped with uncommitted files.' }),
      row({ id: 'shipped', title: 'Shipped one', state: 'shipped' }),
      row({ id: 'canceled', title: 'Canceled one', state: 'canceled', detail: 'Superseded by the installed path.' }),
    ]} />)

    expect(within(screen.getByRole('region', { name: /Asked/ })).getByText('Asked one')).toBeInTheDocument()
    expect(within(screen.getByRole('region', { name: /In flight/ })).getByText('Flying one')).toBeInTheDocument()
    expect(within(screen.getByRole('region', { name: /Blocked — needs you/ })).getByText('Blocked one')).toBeInTheDocument()
    expect(within(screen.getByRole('region', { name: /Needs recovery/ })).getByText('Recovery one')).toBeInTheDocument()
    const closed = screen.getByRole('region', { name: /Closed/ })
    expect(within(closed).getByText('Shipped one')).toBeInTheDocument()
    expect(within(closed).getByText('Canceled one')).toBeInTheDocument()
  })

  it('keeps only the blocked column actionable', () => {
    render(<RequestsBoard requests={[row({ id: 'blocked', title: 'Choose release', state: 'blocked_needs_owner', detail: 'Which release should ship?' })]} />)
    const blocked = screen.getByRole('region', { name: /Blocked — needs you/ })
    expect(within(blocked).getByText('Answer needed')).toBeInTheDocument()
    expect(within(blocked).getByText('Which release should ship?')).toBeInTheDocument()
    expect(within(blocked).getByRole('textbox', { name: /Answer for Choose release/ })).toBeInTheDocument()
  })

  it('renders honest empty states', () => {
    render(<RequestsBoard requests={[]} />)
    expect(screen.getByText('Nothing waiting')).toBeInTheDocument()
    expect(screen.getByText('Nothing in flight')).toBeInTheDocument()
    expect(screen.getByText('Nothing needs you.')).toBeInTheDocument()
    expect(screen.getByText('Nothing to recover')).toBeInTheDocument()
    expect(screen.getByText('Nothing closed yet')).toBeInTheDocument()
  })
})

describe('RequestsBoard filtering and evidence', () => {
  it('searches request words and filters by project', () => {
    render(<RequestsBoard requests={[
      row({ id: 'translation', title: 'Improve translation', project: 'multideal' }),
      row({ id: 'deploy', title: 'Repair deploy', project: 'Overdeck' }),
    ]} />)
    fireEvent.change(screen.getByRole('textbox', { name: 'Search requests' }), { target: { value: 'translation' } })
    expect(screen.getByText('Improve translation')).toBeInTheDocument()
    expect(screen.queryByText('Repair deploy')).not.toBeInTheDocument()
    fireEvent.change(screen.getByRole('textbox', { name: 'Search requests' }), { target: { value: '' } })
    fireEvent.click(screen.getByRole('button', { name: 'Overdeck' }))
    expect(screen.getByText('Repair deploy')).toBeInTheDocument()
    expect(screen.queryByText('Improve translation')).not.toBeInTheDocument()
  })

  it('does not invent in-flight metadata or unsafe proof links', () => {
    render(<RequestsBoard requests={[
      row({ id: 'flight', title: 'Flying', state: 'in_flight' }),
      row({ id: 'unsafe', title: 'Unsafe proof', state: 'shipped', proof_url: 'javascript:alert(1)' }),
    ]} />)
    const card = screen.getByText('Flying').closest('button')!
    expect(within(card).getByText('Current step not recorded')).toBeInTheDocument()
    expect(within(card).getByText(/Lane: not recorded/)).toBeInTheDocument()
    expect(within(card).getByText('heartbeat not recorded')).toBeInTheDocument()
    expect(within(card).getByText('Last event not recorded')).toBeInTheDocument()
    expect(screen.getByText(/limit not recorded/)).toBeInTheDocument()
    expect(screen.getByText('feed freshness not recorded')).toBeInTheDocument()
    expect(screen.queryByRole('link', { name: /Open proof/ })).not.toBeInTheDocument()
    expect(screen.getByText('Proof not recorded')).toBeInTheDocument()
  })

  it('derives delivery history only from landed or deployed receipts', () => {
    render(<RequestsBoard requests={[row({
      id: 'delivery',
      title: 'Delivered request',
      receipt_trail: [
        { id: 'progress', request_id: 'delivery', at: '2026-08-14T01:00:00Z', kind: 'progress', line: 'Tests passed' },
        { id: 'deployed', request_id: 'delivery', at: '2026-08-14T02:00:00Z', kind: 'deployed', line: 'Deployed preview' },
      ],
    })]} />)
    const disclosure = screen.getByText('Deliveries').closest('details')!
    expect(disclosure).not.toHaveAttribute('open')
    expect(within(disclosure).getByText('1 recorded events')).toBeInTheDocument()
    expect(within(disclosure).getByText('Deployed preview')).toBeInTheDocument()
    expect(within(disclosure).queryByText('Tests passed')).not.toBeInTheDocument()
  })
})

describe('RequestsBoard interactions', () => {
  it('shows and copies the exact request reference without using it as the title', async () => {
    const writeText = vi.fn().mockResolvedValue(undefined)
    Object.defineProperty(navigator, 'clipboard', { configurable: true, value: { writeText } })
    render(<RequestsBoard requests={[row({ id: 'req-asked', title: 'Asked', state: 'asked' })]} />)

    expect(screen.getByText('Request req-asked')).toBeInTheDocument()
    fireEvent.click(screen.getByRole('button', { name: 'Copy request ID req-asked' }))
    await vi.waitFor(() => expect(writeText).toHaveBeenCalledWith('req-asked'))
    expect(screen.getByText('Copied')).toBeInTheDocument()
  })

  it('calls onSelect with the row id', () => {
    const clicks: string[] = []
    render(<RequestsBoard requests={[row({ id: 'clicked-key', title: 'Click me' })]} onSelect={(id) => clicks.push(id)} />)
    fireEvent.click(screen.getByText('Click me'))
    expect(clicks).toEqual(['clicked-key'])
  })
})
