import React from 'react'
import '@testing-library/jest-dom'
import userEvent from '@testing-library/user-event'
import { render, screen } from '@testing-library/react'
import { ContextMenu } from './ContextMenu'
import { MatcherFunction } from '@testing-library/dom/types/matches'

test('Closes properly', () => {
  const onClose = jest.fn()
  const { container } = render(
    <ContextMenu
      cursorIndex={{ col: 0, row: 0 }}
      clientX={0}
      clientY={0}
      items={[]}
      close={onClose}
    />
  )
  userEvent.click(container)
  expect(onClose).toHaveBeenCalled()
})

test('Click on item', () => {
  const onClose = jest.fn()
  const onInsertRowBelow = jest.fn()
  render(
    <ContextMenu
      cursorIndex={{ col: 0, row: 0 }}
      clientX={0}
      clientY={0}
      items={[{ type: 'INSERT_ROW_BELLOW', action: onInsertRowBelow }]}
      close={onClose}
    />
  )
  userEvent.click(screen.getByText('Insert row below'))
  expect(onInsertRowBelow).toHaveBeenCalled()
  expect(onClose).not.toHaveBeenCalled()
})

const textContentMatcher = (text: string): MatcherFunction => {
  const hasText = (node: Element | null) => node?.textContent === text

  return function (_, node) {
    const nodeHasText = hasText(node)
    const childrenDontHaveText = Array.from(node?.children ?? []).every(
      (child) => !hasText(child)
    )
    return nodeHasText && childrenDontHaveText
  }
}

test('Check all items', () => {
  render(
    <ContextMenu
      cursorIndex={{ col: 0, row: 0 }}
      clientX={0}
      clientY={0}
      items={[
        { type: 'INSERT_ROW_BELLOW', action: () => null },
        { type: 'DELETE_ROW', action: () => null },
        { type: 'DUPLICATE_ROW', action: () => null },
        { type: 'DELETE_ROWS', fromRow: 1, toRow: 3, action: () => null },
        { type: 'DUPLICATE_ROWS', fromRow: 5, toRow: 7, action: () => null },
      ]}
      close={() => null}
    />
  )
  expect(screen.getByText('Insert row below')).toBeInTheDocument()
  expect(screen.getByText('Delete row')).toBeInTheDocument()
  expect(screen.getByText('Duplicate row')).toBeInTheDocument()
  expect(
    screen.getByText(textContentMatcher('Delete rows 1 to 3'))
  ).toBeInTheDocument()
  expect(
    screen.getByText(textContentMatcher('Duplicate rows 5 to 7'))
  ).toBeInTheDocument()
})

test('Fallback for unknown item', () => {
  render(
    <ContextMenu
      cursorIndex={{ col: 0, row: 0 }}
      clientX={0}
      clientY={0}
      items={[
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        { type: 'UNKNOWN_ITEM', action: () => null },
      ]}
      close={() => null}
    />
  )
  expect(screen.getByText('UNKNOWN_ITEM')).toBeInTheDocument()
})