import '@testing-library/jest-dom'
import { axe, toHaveNoViolations } from 'jest-axe'
import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
import { CustomElementFor } from '../../tests/component-registry'
import './backlink'

expect.extend(toHaveNoViolations)

export interface BacklinkTestConfig extends BaseTestConfig {
  href?: string
  text?: string
  ariaLabel?: string
}

// Use shared framework
export const createBacklinkTest = async (config: BacklinkTestConfig = {}) => {
  const { container, element } = await createElementTest<
    CustomElementFor<'pkt-backlink'>,
    BacklinkTestConfig
  >('pkt-backlink', config)

  return {
    container,
    backlink: element,
  }
}

describe('PktBackLink', () => {
  describe('Rendering and basic functionality', () => {
    test('renders without errors', async () => {
      const { backlink } = await createBacklinkTest()

      expect(backlink).toBeInTheDocument()
      expect(backlink).toBeTruthy()

      const nav = backlink.querySelector('nav')
      expect(nav).toBeInTheDocument()
    })

    test('renders with correct structure', async () => {
      const { backlink } = await createBacklinkTest()

      const nav = backlink.querySelector('nav')
      const link = nav?.querySelector('a')
      const icon = link?.querySelector('pkt-icon')
      const textSpan = link?.querySelector('.pkt-back-link__text')

      expect(nav).toHaveClass('pkt-back-link')
      expect(link).toHaveClass('pkt-link')
      expect(link).toHaveClass('pkt-link--icon-left')
      expect(icon).toHaveClass('pkt-back-link__icon')
      expect(icon).toHaveClass('pkt-icon')
      expect(icon).toHaveClass('pkt-link__icon')
      expect(textSpan).toHaveClass('pkt-back-link__text')
    })

    test('renders icon correctly', async () => {
      const { backlink } = await createBacklinkTest()

      const icon = backlink.querySelector('pkt-icon')
      expect(icon).toBeInTheDocument()
      expect(icon?.getAttribute('name')).toBe('chevron-thin-left')
      expect(icon?.getAttribute('aria-hidden')).toBe('true')
    })
  })

  describe('Properties and attributes', () => {
    test('applies default properties correctly', async () => {
      const { backlink } = await createBacklinkTest()

      expect(backlink.href).toBe('')
      expect(backlink.text).toBe('Forsiden')
      expect(backlink.ariaLabel).toBe('')

      const nav = backlink.querySelector('nav')
      const link = nav?.querySelector('a')
      const textSpan = link?.querySelector('.pkt-back-link__text')

      expect(link?.getAttribute('href')).toBe('/')
      expect(textSpan?.textContent).toBe('Forsiden')
      expect(nav?.getAttribute('aria-label')).toBe('Gå tilbake til forrige side')
    })

    test('handles href property correctly', async () => {
      const { backlink } = await createBacklinkTest({ href: '/previous-page' })

      expect(backlink.href).toBe('/previous-page')

      const link = backlink.querySelector('a')
      expect(link?.getAttribute('href')).toBe('/previous-page')

      // Test href updates
      backlink.href = '/another-page'
      await backlink.updateComplete

      expect(link?.getAttribute('href')).toBe('/another-page')
    })

    test('handles text property correctly', async () => {
      const { backlink } = await createBacklinkTest({ text: 'Back to Home' })

      expect(backlink.text).toBe('Back to Home')
      // The text attribute should be removed from the custom element
      expect(backlink.getAttribute('text')).toBe(null)

      const textSpan = backlink.querySelector('.pkt-back-link__text')
      expect(textSpan?.textContent).toBe('Back to Home')

      // Test text updates
      backlink.text = 'Return to Start'
      await backlink.updateComplete

      expect(textSpan?.textContent).toBe('Return to Start')
    })

    test('handles ariaLabel property correctly', async () => {
      const { backlink } = await createBacklinkTest({
        ariaLabel: 'Navigate back to previous section',
      })

      expect(backlink.ariaLabel).toBe('Navigate back to previous section')

      const nav = backlink.querySelector('nav')
      expect(nav?.getAttribute('aria-label')).toBe('Navigate back to previous section')

      // Test ariaLabel updates
      backlink.ariaLabel = 'Go back to main menu'
      await backlink.updateComplete

      expect(nav?.getAttribute('aria-label')).toBe('Go back to main menu')
    })

    test('uses default aria-label when none provided', async () => {
      const { backlink } = await createBacklinkTest()

      expect(backlink.ariaLabel).toBe('')

      const nav = backlink.querySelector('nav')
      expect(nav?.getAttribute('aria-label')).toBe('Gå tilbake til forrige side')
    })

    test('handles empty href by defaulting to "/"', async () => {
      const { backlink } = await createBacklinkTest({ href: '' })

      expect(backlink.href).toBe('')

      const link = backlink.querySelector('a')
      expect(link?.getAttribute('href')).toBe('/')
    })
  })

  describe('Attribute cleanup', () => {
    test('removes reflected attributes from the element', async () => {
      const { backlink } = await createBacklinkTest({ href: '/test', text: 'Test Text' })

      // The attributeChangedCallback should remove these attributes from the element
      // (this is implementation-specific behavior in the component)
      expect(backlink.hasAttribute('href')).toBe(false)
      expect(backlink.hasAttribute('text')).toBe(false)
      expect(backlink.hasAttribute('arialabel')).toBe(false)
    })
  })

  describe('Link functionality', () => {
    test('creates clickable link with correct href', async () => {
      const { backlink } = await createBacklinkTest({
        href: '/dashboard',
        text: 'Back to Dashboard',
      })

      const link = backlink.querySelector('a')
      expect(link).toBeInTheDocument()
      expect(link?.getAttribute('href')).toBe('/dashboard')
      expect(link?.textContent?.trim()).toContain('Back to Dashboard')
    })

    test('handles complex URLs correctly', async () => {
      const complexUrl = 'https://example.com/path?query=value#section'
      const { backlink } = await createBacklinkTest({ href: complexUrl })

      const link = backlink.querySelector('a')
      expect(link?.getAttribute('href')).toBe(complexUrl)
    })
  })

  describe('Accessibility', () => {
    test('has correct ARIA attributes', async () => {
      const { backlink } = await createBacklinkTest({
        text: 'Home',
        ariaLabel: 'Return to main page',
      })

      const nav = backlink.querySelector('nav')
      const icon = backlink.querySelector('pkt-icon')

      expect(nav?.getAttribute('aria-label')).toBe('Return to main page')
      expect(icon?.getAttribute('aria-hidden')).toBe('true')
    })

    test('provides semantic navigation structure', async () => {
      const { backlink } = await createBacklinkTest()

      const nav = backlink.querySelector('nav')
      const link = nav?.querySelector('a')

      expect(nav).toBeInTheDocument()
      expect(link).toBeInTheDocument()
      expect(nav?.tagName.toLowerCase()).toBe('nav')
      expect(link?.tagName.toLowerCase()).toBe('a')
    })

    test('renders with no WCAG errors with axe - default backlink', async () => {
      const { container } = await createBacklinkTest()

      const results = await axe(container)
      expect(results).toHaveNoViolations()
    })

    test('renders with no WCAG errors with axe - custom backlink', async () => {
      const { container } = await createBacklinkTest({
        href: '/categories',
        text: 'Back to Categories',
        ariaLabel: 'Navigate back to category listing',
      })

      const results = await axe(container)
      expect(results).toHaveNoViolations()
    })

    test('renders with no WCAG errors with axe - external link', async () => {
      const { container } = await createBacklinkTest({
        href: 'https://example.com',
        text: 'Back to External Site',
      })

      const results = await axe(container)
      expect(results).toHaveNoViolations()
    })
  })
})
