import type { Topic } from '../../types'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { useEdgesInteractions } from '../../../../hooks/use-edges-interactions'
import ClassList from '../class-list'

vi.mock('react-sortablejs', () => ({
  __esModule: true,
  ReactSortable: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}))

vi.mock('../../../../hooks/use-edges-interactions', async (importOriginal) => {
  const actual = await importOriginal<typeof import('../../../../hooks/use-edges-interactions')>()
  return {
    ...actual,
    useEdgesInteractions: vi.fn(),
  }
})

vi.mock('../class-item', () => ({
  __esModule: true,
  default: ({
    payload,
    onChange,
    onRemove,
    index,
  }: {
    payload: Topic
    onChange: (value: Topic) => void
    onRemove: () => void
    index: number
  }) => (
    <div>
      <div>{`${index}:${payload.name}`}</div>
      <button
        type="button"
        onClick={() => onChange({ ...payload, name: `${payload.name} updated` })}
      >
        change-item
      </button>
      <button type="button" onClick={onRemove}>
        remove-item
      </button>
    </div>
  ),
}))

const mockUseEdgesInteractions = vi.mocked(useEdgesInteractions)

const createTopic = (overrides: Partial<Topic> = {}): Topic => ({
  id: 'topic-1',
  name: 'Billing questions',
  ...overrides,
})

describe('question-classifier/class-list', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockUseEdgesInteractions.mockReturnValue({
      handleEdgeDeleteByDeleteBranch: vi.fn(),
    } as unknown as ReturnType<typeof useEdgesInteractions>)
  })

  it('adds, updates, collapses, and removes classes through the list actions', async () => {
    const user = userEvent.setup()
    const onChange = vi.fn()
    const handleEdgeDeleteByDeleteBranch = vi.fn()
    mockUseEdgesInteractions.mockReturnValueOnce({
      handleEdgeDeleteByDeleteBranch,
    } as unknown as ReturnType<typeof useEdgesInteractions>)

    render(
      <ClassList
        nodeId="node-1"
        list={[createTopic(), createTopic({ id: 'topic-2', name: 'Refunds' })]}
        onChange={onChange}
        filterVar={() => true}
      />,
    )

    await user.click(screen.getAllByText('change-item')[0]!)
    expect(onChange).toHaveBeenCalledWith(
      expect.arrayContaining([expect.objectContaining({ name: 'Billing questions updated' })]),
    )

    await user.click(screen.getAllByText('remove-item')[0]!)
    expect(handleEdgeDeleteByDeleteBranch).toHaveBeenCalledWith('node-1', 'topic-1')

    await user.click(
      screen.getByRole('button', { name: /workflow\.nodes\.questionClassifiers\.class/ }),
    )
    expect(
      screen.queryByText('workflow.nodes.questionClassifiers.addClass'),
    ).not.toBeInTheDocument()

    await user.click(
      screen.getByRole('button', { name: /workflow\.nodes\.questionClassifiers\.class/ }),
    )
    await user.click(screen.getByText('workflow.nodes.questionClassifiers.addClass'))
    expect(onChange).toHaveBeenCalledWith(
      expect.arrayContaining([expect.objectContaining({ name: '' })]),
    )
  })

  it('hides drag and add affordances when readonly', () => {
    const { container } = render(
      <ClassList
        nodeId="node-1"
        list={[createTopic(), createTopic({ id: 'topic-2', name: 'Refunds' })]}
        onChange={vi.fn()}
        filterVar={() => true}
        readonly
      />,
    )

    expect(
      screen.queryByText('workflow.nodes.questionClassifiers.addClass'),
    ).not.toBeInTheDocument()
    expect(container.querySelector('.handle')).toBeNull()
  })
})
