import '@testing-library/jest-dom'

import { fireEvent, render, screen } from '@testing-library/react'
import { axe, toHaveNoViolations } from 'jest-axe'
import { ChangeEvent, useState } from 'react'
import { vi } from 'vitest'

import { PktSearchInput } from './SearchInput'

expect.extend(toHaveNoViolations)

const Wrapper = (props: { onChange: (e: ChangeEvent) => void }) => {
  const [value, setValue] = useState('')
  return (
    <PktSearchInput
      id="test-search-input"
      label="Test Label"
      value={value}
      onChange={props.onChange}
      onSearch={(value: string) => setValue(value)}
    />
  )
}

describe('PktSearchInput', () => {
  it('renders with form element when action prop exists', async () => {
    const { container } = render(<PktSearchInput id="test-search-input" action="/search" />)
    await window.customElements.whenDefined('pkt-icon')
    expect(container.querySelector('form')).toBeInTheDocument()
  })

  it('renders with div element when action prop does not exist', async () => {
    const { container } = render(<PktSearchInput id="test-search-input" />)
    await window.customElements.whenDefined('pkt-icon')
    expect(container.querySelector('div')).toBeInTheDocument()
    expect(container.querySelector('form')).not.toBeInTheDocument()
  })

  it('renders with label element when label prop exists', async () => {
    const { container } = render(<PktSearchInput id="test-search-input" label="Test Label" />)
    await window.customElements.whenDefined('pkt-icon')
    expect(container.querySelector('label')).toBeInTheDocument()
  })

  it('renders with div element when label prop does not exist', async () => {
    const { container } = render(<PktSearchInput id="test-search-input" />)
    await window.customElements.whenDefined('pkt-icon')
    expect(container.querySelector('div')).toBeInTheDocument()
    expect(container.querySelector('label')).not.toBeInTheDocument()
  })

  it('calls onSearch prop with input value on button click', async () => {
    const mockOnSearch = vi.fn()
    const { getByRole, getByPlaceholderText } = render(<Wrapper onChange={mockOnSearch} />)
    await window.customElements.whenDefined('pkt-icon')

    const inputElement = getByPlaceholderText('Søk…')
    const buttonElement = getByRole('button')

    // Type a value in the input
    fireEvent.input(inputElement, { target: { value: 'test value' } })

    // Click the button
    fireEvent.click(buttonElement)

    // Check if onSearch was called with the correct value
    expect(mockOnSearch).toHaveBeenCalledWith(
      expect.objectContaining({ target: expect.objectContaining({ value: 'test value' }) }),
    )
  })

  it('renders search suggestions when suggestions prop exists', async () => {
    const suggestions = [
      { title: 'Suggestion 1', onClick: vi.fn() },
      { title: 'Suggestion 2', onClick: vi.fn() },
    ]

    render(<PktSearchInput id="test-search-input" suggestions={suggestions} />)
    await window.customElements.whenDefined('pkt-icon')

    // Check if suggestion elements are rendered
    suggestions.forEach((suggestion) => {
      expect(screen.getByText(suggestion.title)).toBeInTheDocument()
    })
  })

  describe('accessibility', () => {
    it('renders with no wcag errors with axe', async () => {
      const suggestions = [
        { title: 'Suggestion 1', onClick: vi.fn() },
        { title: 'Suggestion 2', onClick: vi.fn() },
      ]
      const { container } = render(<PktSearchInput id="test-search-input" label="My label" suggestions={suggestions} />)
      await window.customElements.whenDefined('pkt-icon')
      const results = await axe(container)
      expect(results).toHaveNoViolations()
    })
  })
})
