import '@testing-library/jest-dom'

import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
import { EXAMPLE_HEADER_FOOTER_DATA } from 'shared-utils/header-footer'
import { afterEach, describe, expect, test, vi } from 'vitest'

import { PktHeaderGlobal } from './HeaderGlobal'

const renderGlobal = (props = {}) =>
  render(<PktHeaderGlobal data={EXAMPLE_HEADER_FOOTER_DATA} position="relative" {...props} />)

// jsdom reports offsetWidth as 0, which puts the header in compact mode.
// Force the desktop (full) layout by zeroing the breakpoints.
const DESKTOP = { mobileBreakpoint: 0, tabletBreakpoint: 0 }

afterEach(() => {
  vi.unstubAllGlobals()
})

describe('PktHeaderGlobal', () => {
  test('viser søkefelt, kontaktlenke og menyknapp (desktop)', () => {
    const { container } = renderGlobal(DESKTOP)

    expect(container.querySelector('input[name="q"]')).toBeInTheDocument()

    const contact = screen.getByRole('link', { name: 'Kontakt' })
    expect(contact).toHaveAttribute('href', 'https://www.oslo.kommune.no/kontakt')

    expect(screen.getByRole('button', { name: /Meny/ })).toBeInTheDocument()
  })

  test('søkefeltet er en GET-form mot søke-endepunktet (desktop)', () => {
    const { container } = renderGlobal(DESKTOP)
    const form = container.querySelector('form[role="search"]')
    expect(form).toHaveAttribute('action', 'https://www.oslo.kommune.no/sokeresultat/')
    expect(form).toHaveAttribute('method', 'get')
  })

  test('mobil: søkeknappen åpner et søkefelt-overlay', () => {
    const { container } = renderGlobal()
    // Compact layout: inline search is replaced by a round toggle.
    expect(container.querySelector('.pkt-header-global__search-panel')).not.toBeInTheDocument()
    const searchToggle = container.querySelector('#pkt-header-global-search-toggle')
    expect(searchToggle).toBeInTheDocument()

    fireEvent.click(searchToggle as Element)

    const panel = container.querySelector('.pkt-header-global__search-panel')
    expect(panel).toBeInTheDocument()
    expect(panel?.querySelector('input[name="q"]')).toBeInTheDocument()
  })

  test('mobil: åpning av søk gir fokus til søkefeltet', () => {
    const { container } = renderGlobal()
    fireEvent.click(container.querySelector('#pkt-header-global-search-toggle') as Element)

    const input = container.querySelector('#pkt-header-global-search-panel input') as HTMLInputElement
    expect(input).toBeTruthy()
    expect(document.activeElement).toBe(input)
  })

  test('mobil: Tab ut av søke-overlay lukker det og flytter fokus til søkeknappen', () => {
    const { container } = renderGlobal()
    const searchToggle = container.querySelector('#pkt-header-global-search-toggle') as HTMLElement
    fireEvent.click(searchToggle)

    const panel = container.querySelector('#pkt-header-global-search-panel') as HTMLElement
    const focusables = panel.querySelectorAll<HTMLElement>('input, button')
    const last = focusables[focusables.length - 1]
    act(() => last.focus())

    fireEvent.keyDown(document, { key: 'Tab' })

    expect(container.querySelector('.pkt-header-global__search-panel')).not.toBeInTheDocument()
    expect(searchToggle.contains(document.activeElement) || document.activeElement === searchToggle).toBe(true)
  })

  test('mobil: fokus utenfor søke-overlay lukker det', () => {
    const { container } = renderGlobal()
    fireEvent.click(container.querySelector('#pkt-header-global-search-toggle') as Element)
    expect(container.querySelector('.pkt-header-global__search-panel')).toBeInTheDocument()

    const menuToggle = container.querySelector('#pkt-header-global-menu-toggle') as HTMLElement
    act(() => menuToggle.focus())
    fireEvent.focusIn(menuToggle)

    expect(container.querySelector('.pkt-header-global__search-panel')).not.toBeInTheDocument()
  })

  test('mobil: åpning av søk lukker megamenyen', () => {
    const { container } = renderGlobal()
    fireEvent.click(screen.getByRole('button', { name: /Meny/ }))
    expect(screen.getByText('Tjenester og tilbud')).toBeInTheDocument()

    fireEvent.click(container.querySelector('#pkt-header-global-search-toggle') as Element)
    expect(screen.queryByText('Tjenester og tilbud')).not.toBeInTheDocument()
    expect(container.querySelector('.pkt-header-global__search-panel')).toBeInTheDocument()
  })

  test('menyknappen åpner megamenyen', () => {
    renderGlobal()
    expect(screen.queryByText('Tjenester og tilbud')).not.toBeInTheDocument()

    fireEvent.click(screen.getByRole('button', { name: /Meny/ }))

    expect(screen.getByText('Tjenester og tilbud')).toBeInTheDocument()
  })

  test('tastatur: Tab fra menyknappen flytter fokus inn i megamenyen', () => {
    const { container } = renderGlobal(DESKTOP)
    const toggle = container.querySelector('#pkt-header-global-menu-toggle') as HTMLElement
    fireEvent.click(toggle)
    act(() => toggle.focus())
    expect(document.activeElement).toBe(toggle)

    fireEvent.keyDown(document, { key: 'Tab' })

    const menu = container.querySelector('#pkt-header-global-menu') as HTMLElement
    const firstFocusable = menu.querySelector('a[href], button') as HTMLElement
    expect(document.activeElement).toBe(firstFocusable)
  })

  test('mobil: Tab fra menyknappen flytter fokus inn i megamenyen (accordion)', () => {
    const original = window.matchMedia
    // Force the mega menu into its mobile accordion layout.
    window.matchMedia = vi.fn().mockReturnValue({
      matches: true,
      addEventListener: vi.fn(),
      removeEventListener: vi.fn(),
      addListener: vi.fn(),
      removeListener: vi.fn(),
    }) as unknown as typeof window.matchMedia
    try {
      const { container } = renderGlobal()
      const toggle = container.querySelector('#pkt-header-global-menu-toggle') as HTMLElement
      fireEvent.click(toggle)
      act(() => toggle.focus())

      fireEvent.keyDown(document, { key: 'Tab' })

      const menu = container.querySelector('#pkt-header-global-menu') as HTMLElement
      const firstSummary = menu.querySelector('summary') as HTMLElement
      expect(firstSummary).toBeTruthy()
      expect(document.activeElement).toBe(firstSummary)
    } finally {
      window.matchMedia = original
    }
  })

  test('tastatur: Tab ut av megamenyen lukker den og flytter fokus til menyknappen', () => {
    const { container } = renderGlobal(DESKTOP)
    const toggle = container.querySelector('#pkt-header-global-menu-toggle') as HTMLElement
    fireEvent.click(toggle)

    const menu = container.querySelector('#pkt-header-global-menu') as HTMLElement
    const focusables = menu.querySelectorAll<HTMLElement>('a[href], button')
    const last = focusables[focusables.length - 1]
    act(() => last.focus())

    fireEvent.keyDown(document, { key: 'Tab' })

    expect(container.querySelector('#pkt-header-global-menu')).not.toBeInTheDocument()
    expect(toggle.contains(document.activeElement) || document.activeElement === toggle).toBe(true)
  })

  test('tastatur: fokus utenfor megamenyen lukker den', () => {
    const { container } = renderGlobal(DESKTOP)
    fireEvent.click(container.querySelector('#pkt-header-global-menu-toggle') as Element)
    expect(screen.getByText('Tjenester og tilbud')).toBeInTheDocument()

    const contact = container.querySelector('.pkt-header-global__contact') as HTMLElement
    act(() => contact.focus())
    fireEvent.focusIn(contact)

    expect(screen.queryByText('Tjenester og tilbud')).not.toBeInTheDocument()
  })

  test('viser feilmelding i menyen når data ikke kan lastes', async () => {
    vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new Error('network')))
    render(<PktHeaderGlobal position="relative" {...DESKTOP} />)

    const menuButton = await screen.findByRole('button', { name: /Meny/ })
    await waitFor(() => expect(menuButton).not.toBeDisabled())

    fireEvent.click(menuButton)
    expect(screen.getByText('Kunne ikke laste meny.')).toBeInTheDocument()
  })

  test('brukerknappen åpner brukermenyen', () => {
    renderGlobal({ user: { name: 'Aksel Web Opdahl' }, logOutButtonPlacement: 'userMenu', logOut: vi.fn() })

    const userButton = screen.getByRole('button', { name: /Aksel Web Opdahl/ })
    fireEvent.click(userButton)

    expect(screen.getByText('Pålogget som')).toBeInTheDocument()
  })

  test('kaller onDataLoaded når data er forhåndshentet', () => {
    const onDataLoaded = vi.fn()
    renderGlobal({ onDataLoaded })
    expect(onDataLoaded).toHaveBeenCalledWith(EXAMPLE_HEADER_FOOTER_DATA)
  })

  test('logo lenker til www.oslo.kommune.no når logoLink er satt', () => {
    renderGlobal({ logoLink: 'https://www.oslo.kommune.no' })
    const logoLink = screen.getByRole('link', { name: 'Til hovedsiden' })
    expect(logoLink).toHaveAttribute('href', 'https://www.oslo.kommune.no')
  })

  test('skjuler kontaktlenken når bruker er innlogget', () => {
    const { container } = renderGlobal({ ...DESKTOP, user: { name: 'Aksel Web Opdahl' } })
    expect(container.querySelector('.pkt-header-global__contact')).not.toBeInTheDocument()
    expect(container.querySelector('.pkt-header-global__user-button')).toBeInTheDocument()
  })

  test('megameny-overlegget forankres til headerens faktiske posisjon', () => {
    const { container } = renderGlobal({ ...DESKTOP, position: 'relative' })
    const header = container.querySelector('.pkt-header-global') as HTMLElement
    // Simulate a header sitting 32px down the page (relative/sticky position).
    header.getBoundingClientRect = () =>
      ({ bottom: 120, top: 32, left: 16, right: 1296, width: 1280, height: 88 }) as DOMRect

    fireEvent.click(container.querySelector('#pkt-header-global-menu-toggle') as Element)

    const overlay = container.querySelector('#pkt-header-global-menu') as HTMLElement
    // The CSS adds the design offset (104/88px) on top of this anchor.
    expect(overlay.style.getPropertyValue('--pkt-header-global-top')).toBe('32px')
    expect(overlay.style.getPropertyValue('--pkt-header-global-left')).toBe('16px')
    expect(overlay.style.getPropertyValue('--pkt-header-global-width')).toBe('1280px')
  })

  test('position="sticky" gir sticky-klasse uten wrapper/spacer', () => {
    const { container } = renderGlobal({ ...DESKTOP, position: 'sticky' })
    const header = container.querySelector('.pkt-header-global')
    expect(header).toHaveClass('pkt-header-global--sticky')
    expect(header).not.toHaveClass('pkt-header-global--fixed')
    expect(container.querySelector('.pkt-header-global-wrapper')).toBeNull()
    expect(container.querySelector('.pkt-header-global-spacer')).toBeNull()
  })

  test('logoen lenker til www.oslo.kommune.no som standard', () => {
    const { container } = renderGlobal(DESKTOP)
    const logo = container.querySelector('.pkt-header-global__logo a')
    expect(logo).toHaveAttribute('href', 'https://www.oslo.kommune.no')
  })

  test('logoClick kalles ved klikk på logoen', () => {
    // preventDefault: jsdom kan ikke navigere
    const onClick = vi.fn((e: React.MouseEvent) => e.preventDefault())
    const { container } = renderGlobal({ ...DESKTOP, logoClick: onClick })
    fireEvent.click(container.querySelector('.pkt-header-global__logo a') as Element)
    expect(onClick).toHaveBeenCalledTimes(1)
  })
})
