import { describe, it, expect, vi } from 'vitest'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { RouteFlow } from './RouteFlow'

const nodes = [
  { name: 'jms:orders', type: 'from' as const, durationMs: 4, status: 'ok' as const },
  { name: 'OrderValidator', type: 'process' as const, durationMs: 8, status: 'ok' as const },
  { name: 'http:payment-api', type: 'to' as const, durationMs: 187, status: 'slow' as const },
  { name: 'dead-letter:failed', type: 'error-handler' as const, durationMs: 14, status: 'fail' as const },
]

describe('RouteFlow', () => {
  it('renders node names', () => {
    render(<RouteFlow nodes={nodes} />)
    expect(screen.getByText('jms:orders')).toBeInTheDocument()
    expect(screen.getByText('OrderValidator')).toBeInTheDocument()
    expect(screen.getByText('http:payment-api')).toBeInTheDocument()
    expect(screen.getByText('dead-letter:failed')).toBeInTheDocument()
  })

  it('does not render action trigger when no actions provided', () => {
    const { container } = render(<RouteFlow nodes={nodes} />)
    expect(container.querySelector('[aria-label*="Actions for"]')).not.toBeInTheDocument()
  })

  it('renders action trigger on all nodes including error handlers when actions provided', () => {
    const { container } = render(
      <RouteFlow
        nodes={nodes}
        actions={[{ label: 'View Config', onClick: () => {} }]}
      />,
    )
    const triggers = container.querySelectorAll('[aria-label*="Actions for"]')
    expect(triggers.length).toBe(4) // 3 main + 1 error handler
  })

  it('clicking action trigger does not fire onNodeClick', async () => {
    const onNodeClick = vi.fn()
    const user = userEvent.setup()
    const { container } = render(
      <RouteFlow
        nodes={nodes}
        onNodeClick={onNodeClick}
        actions={[{ label: 'Test Action', onClick: () => {} }]}
      />,
    )
    const trigger = container.querySelector('[aria-label="Actions for jms:orders"]')!
    await user.click(trigger)
    expect(onNodeClick).not.toHaveBeenCalled()
  })

  it('calls action onClick when menu item clicked', async () => {
    const actionClick = vi.fn()
    const user = userEvent.setup()
    const { container } = render(
      <RouteFlow
        nodes={nodes}
        actions={[{ label: 'Change Log Level', onClick: actionClick }]}
      />,
    )
    const trigger = container.querySelector('[aria-label="Actions for jms:orders"]')!
    await user.click(trigger)
    await user.click(screen.getByText('Change Log Level'))
    expect(actionClick).toHaveBeenCalledOnce()
  })

  it('supports dynamic getActions per node', () => {
    const { container } = render(
      <RouteFlow
        nodes={nodes}
        getActions={(node) =>
          node.type === 'process'
            ? [{ label: 'Edit Processor', onClick: () => {} }]
            : []
        }
      />,
    )
    const triggers = container.querySelectorAll('[aria-label*="Actions for"]')
    expect(triggers.length).toBe(1)
    expect(triggers[0]).toHaveAttribute('aria-label', 'Actions for OrderValidator')
  })
})

const multiFlows = [
  {
    label: 'Main Route',
    nodes: [
      { name: 'timer:tick', type: 'from' as const, durationMs: 0, status: 'ok' as const },
      { name: 'Processor1', type: 'process' as const, durationMs: 8, status: 'ok' as const },
    ],
  },
  {
    label: 'onException',
    variant: 'error' as const,
    nodes: [
      { name: 'LogHandler', type: 'process' as const, durationMs: 3, status: 'ok' as const },
      { name: 'dead-letter:errors', type: 'to' as const, durationMs: 8, status: 'fail' as const },
    ],
  },
]

describe('RouteFlow (multi-flow)', () => {
  it('renders all segment labels', () => {
    render(<RouteFlow flows={multiFlows} />)
    expect(screen.getByText('Main Route')).toBeInTheDocument()
    expect(screen.getByText('onException')).toBeInTheDocument()
  })

  it('renders all nodes across segments', () => {
    render(<RouteFlow flows={multiFlows} />)
    expect(screen.getByText('timer:tick')).toBeInTheDocument()
    expect(screen.getByText('Processor1')).toBeInTheDocument()
    expect(screen.getByText('LogHandler')).toBeInTheDocument()
    expect(screen.getByText('dead-letter:errors')).toBeInTheDocument()
  })

  it('uses global flat indexing for onNodeClick', async () => {
    const onNodeClick = vi.fn()
    const user = userEvent.setup()
    render(<RouteFlow flows={multiFlows} onNodeClick={onNodeClick} />)
    // Click the first node of the second flow (global index = 2)
    await user.click(screen.getByText('LogHandler'))
    expect(onNodeClick).toHaveBeenCalledWith(
      expect.objectContaining({ name: 'LogHandler' }),
      2,
    )
  })

  it('selectedIndex highlights correct node across flows', () => {
    const { container } = render(<RouteFlow flows={multiFlows} selectedIndex={3} />)
    // Index 3 = dead-letter:errors (2nd node of 2nd flow)
    const selectedNodes = container.querySelectorAll('[class*="nodeSelected"]')
    expect(selectedNodes.length).toBe(1)
    expect(selectedNodes[0]).toHaveTextContent('dead-letter:errors')
  })

  it('actions work in multi-flow mode', () => {
    const { container } = render(
      <RouteFlow
        flows={multiFlows}
        actions={[{ label: 'Test Action', onClick: () => {} }]}
      />,
    )
    const triggers = container.querySelectorAll('[aria-label*="Actions for"]')
    expect(triggers.length).toBe(4)
  })

  it('flows takes precedence over nodes', () => {
    render(
      <RouteFlow
        nodes={nodes}
        flows={multiFlows}
      />,
    )
    // Should render flow content, not nodes content
    expect(screen.getByText('Main Route')).toBeInTheDocument()
    expect(screen.queryByText('jms:orders')).not.toBeInTheDocument()
  })
})
