import '@testing-library/jest-dom'

import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { axe, toHaveNoViolations } from 'jest-axe'
import { vi } from 'vitest'
import { createRef } from 'react'
import { useForm } from 'react-hook-form'

import { PktButton } from './Button'

expect.extend(toHaveNoViolations)

// Mock Form Component
const MockForm = ({ buttonPosition }: { buttonPosition: 'inside' | 'outside' }) => {
  const { register, handleSubmit, reset } = useForm()
  const onSubmit = vi.fn()

  return (
    <>
      <form id="test-form" onSubmit={handleSubmit(onSubmit)}>
        <input {...register('name')} placeholder="Name" />
        {buttonPosition === 'inside' && <PktButton type="submit">Submit</PktButton>}
        {buttonPosition === 'inside' && (
          <PktButton type="reset" onClick={() => reset()}>
            Reset
          </PktButton>
        )}
      </form>
      {buttonPosition === 'outside' && (
        <PktButton type="submit" form="test-form">
          Submit
        </PktButton>
      )}
      {buttonPosition === 'outside' && (
        <PktButton type="reset" form="test-form" onClick={() => reset()}>
          Reset
        </PktButton>
      )}
    </>
  )
}
// Ligger button utenfor form i React Hook Form må bruker sende inn reset  selv
// dette gjelder ikke native knapper som er assosiert med native form elementer, men de fleste brukerene våre
// bruker nok også våre input elementer også
//https://react-hook-form.com/api/useform/reset

describe('PktButton Form Behavior', () => {
  test('PktButton submits form when inside form element', async () => {
    render(<MockForm buttonPosition="inside" />)

    await userEvent.type(screen.getByPlaceholderText('Name'), 'Shawn Joe')
    await userEvent.click(screen.getByText('Submit'))

    expect(screen.getByPlaceholderText('Name')).toHaveValue('Shawn Joe')
  })

  test('PktButton resets form when inside form element', async () => {
    render(<MockForm buttonPosition="inside" />)

    await userEvent.type(screen.getByPlaceholderText('Name'), 'Shawn Joe')
    await userEvent.click(screen.getByText('Reset'))

    expect(screen.getByPlaceholderText('Name')).toHaveValue('')
  })

  test('PktButton submits form when outside but linked via form attribute', async () => {
    render(<MockForm buttonPosition="outside" />)

    await userEvent.type(screen.getByPlaceholderText('Name'), 'Shawn Joe')
    await userEvent.click(screen.getByText('Submit'))

    expect(screen.getByPlaceholderText('Name')).toHaveValue('Shawn Joe')
  })

  test('PktButton resets form when outside but linked via form attribute', async () => {
    render(<MockForm buttonPosition="outside" />)

    await userEvent.type(screen.getByPlaceholderText('Name'), 'Shawn Joe')
    await userEvent.click(screen.getByText('Reset'))

    // Wait for the form state update
    await screen.findByPlaceholderText('Name')

    expect(screen.getByPlaceholderText('Name')).toHaveValue('')
  })
})

test('forwardRef works correctly', async () => {
  const ref = createRef<HTMLButtonElement>()
  render(<PktButton ref={ref}>Click me</PktButton>)

  await userEvent.click(screen.getByText('Click me'))

  expect(ref.current).toBe(screen.getByRole('button'))
})

test('PktButton triggers click when focused and enter is pressed', async () => {
  const handleClick = vi.fn()
  render(<PktButton onClick={handleClick}>trøkk her</PktButton>)

  const button = screen.getByRole('button', { name: /trøkk her/i })

  button.focus()
  expect(button).toHaveFocus()

  await userEvent.keyboard('{Enter}')
  expect(handleClick).toHaveBeenCalledTimes(1)
})

test('PktButton triggers click when focused and space is pressed', async () => {
  const handleClick = vi.fn()
  render(<PktButton onClick={handleClick}>Trøkk igjen</PktButton>)

  const button = screen.getByRole('button')

  button.focus()
  expect(button).toHaveFocus()

  await userEvent.keyboard(' ')

  expect(handleClick).toHaveBeenCalledTimes(1)
})

describe('accessibility', () => {
  it('renders with no wcag errors with axe', async () => {
    const { container } = render(<PktButton title="Normal" skin="primary"></PktButton>)
    const results = await axe(container)

    expect(results).toHaveNoViolations()
  })
})

describe('PktButton icon paths', () => {
  test('passes iconPath to PktIcon when provided', () => {
    const customPath = 'https://custom-cdn.example.com/icons/'
    render(
      <PktButton variant="icon-left" iconName="user" iconPath={customPath}>
        Test Button
      </PktButton>,
    )

    const icon = document.querySelector('.pkt-btn__icon:not(.pkt-btn__spinner)') as HTMLElement & { path?: string }
    expect(icon?.path).toBe(customPath)
  })

  test('does not set path property when iconPath is not provided', () => {
    render(
      <PktButton variant="icon-left" iconName="user">
        Test Button
      </PktButton>,
    )

    const icon = document.querySelector('.pkt-btn__icon:not(.pkt-btn__spinner)') as HTMLElement & { path?: string }
    // When not provided, path uses PktIcon's default
    expect(icon?.path).toBe('https://punkt-cdn.oslo.kommune.no/latest/icons/')
  })

  test('passes secondIconPath to second PktIcon when provided', () => {
    const customPath = 'https://custom-cdn.example.com/icons/'
    render(
      <PktButton variant="icons-right-and-left" iconName="home" secondIconName="star" secondIconPath={customPath}>
        Test Button
      </PktButton>,
    )

    const icons = document.querySelectorAll('.pkt-btn__icon:not(.pkt-btn__spinner)') as NodeListOf<
      HTMLElement & { path?: string }
    >
    expect(icons).toHaveLength(2)
    expect(icons[1]?.path).toBe(customPath)
  })

  test('handles both iconPath and secondIconPath independently', () => {
    const iconPath = 'https://custom-cdn.example.com/icons/'
    const secondIconPath = 'https://another-cdn.example.com/icons/'
    render(
      <PktButton
        variant="icons-right-and-left"
        iconName="home"
        secondIconName="star"
        iconPath={iconPath}
        secondIconPath={secondIconPath}
      >
        Test Button
      </PktButton>,
    )

    const icons = document.querySelectorAll('.pkt-btn__icon:not(.pkt-btn__spinner)') as NodeListOf<
      HTMLElement & { path?: string }
    >
    expect(icons).toHaveLength(2)
    expect(icons[0]?.path).toBe(iconPath)
    expect(icons[1]?.path).toBe(secondIconPath)
  })
})
