import '@testing-library/jest-dom'
import { axe, toHaveNoViolations } from 'jest-axe'
import { fireEvent } from '@testing-library/dom'

expect.extend(toHaveNoViolations)

import './helptext'
import { PktHelptext } from './helptext'

const waitForCustomElements = async () => {
  await customElements.whenDefined('pkt-helptext')
  await customElements.whenDefined('pkt-icon')
}

// Helper function to create helptext markup
const createHelptext = async (helptextProps = '', content = '') => {
  const container = document.createElement('div')
  container.innerHTML = `
    <pkt-helptext ${helptextProps}>
      ${content}
    </pkt-helptext>
  `
  document.body.appendChild(container)
  await waitForCustomElements()
  return container
}

// Cleanup after each test
afterEach(() => {
  document.body.innerHTML = ''
})

describe('PktHelptext', () => {
  describe('Rendering and basic functionality', () => {
    test('renders without errors', async () => {
      const container = await createHelptext()

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      expect(helptext).toBeInTheDocument()

      await helptext.updateComplete
      expect(helptext).toBeTruthy()
    })

    test('renders with basic helptext', async () => {
      const helptextContent = 'This is helpful information'
      const container = await createHelptext(`helptext="${helptextContent}"`)

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      expect(helptext.helptext).toBe(helptextContent)

      const helptextContainer = helptext.querySelector('.pkt-inputwrapper__helptext-container')
      expect(helptextContainer).toBeInTheDocument()
      expect(helptextContainer).toHaveClass('pkt-inputwrapper__has-helptext')

      const helptextDiv = helptext.querySelector('.pkt-inputwrapper__helptext')
      expect(helptextDiv).toBeInTheDocument()
      expect(helptextDiv?.textContent?.trim()).toContain(helptextContent)
    })

    test('renders with slot content', async () => {
      const slotContent = '<p>Slot helptext content</p>'
      const container = await createHelptext('', slotContent)

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const contentSlot = helptext.querySelector('.pkt-contents')
      expect(contentSlot).toBeInTheDocument()
      expect(helptext.textContent).toContain('Slot helptext content')
    })

    test('renders with dropdown helptext', async () => {
      const dropdownContent = 'This is expandable helptext content'
      const container = await createHelptext(`helptextDropdown="${dropdownContent}"`)

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      expect(helptext.helptextDropdown).toBe(dropdownContent)

      const expandableContainer = helptext.querySelector('.pkt-inputwrapper__helptext-expandable')
      expect(expandableContainer).toBeInTheDocument()

      const button = expandableContainer?.querySelector('button')
      expect(button).toBeInTheDocument()
      expect(button).toHaveClass('pkt-link')

      const icon = button?.querySelector('pkt-icon')
      expect(icon).toBeInTheDocument()
    })
  })

  describe('Properties and attributes', () => {
    test('applies default properties correctly', async () => {
      const container = await createHelptext()

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      expect(helptext.forId).toBeTruthy() // Should have a generated ID
      expect(helptext.helptext).toBe('')
      expect(helptext.helptextDropdown).toBe('')
      expect(helptext.helptextDropdownButton).toBeTruthy() // Should have default from specs
      expect(helptext.isHelpTextOpen).toBe(false)
    })

    test('sets forId correctly', async () => {
      const customId = 'custom-helptext-id'
      const container = await createHelptext(`forId="${customId}"`)

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      expect(helptext.forId).toBe(customId)

      const helptextDiv = helptext.querySelector('.pkt-inputwrapper__helptext')
      expect(helptextDiv?.id).toBe(`${customId}-helptext`)
    })

    test('sets helptext content correctly', async () => {
      const helptextContent = 'Custom helptext message'
      const container = await createHelptext(`helptext="${helptextContent}"`)

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      expect(helptext.helptext).toBe(helptextContent)
      expect(helptext.textContent).toContain(helptextContent)
    })

    test('sets dropdown helptext correctly', async () => {
      const dropdownContent = 'Dropdown helptext content'
      const container = await createHelptext(`helptextDropdown="${dropdownContent}"`)

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      expect(helptext.helptextDropdown).toBe(dropdownContent)
    })

    test('sets dropdown button text correctly', async () => {
      const buttonText = 'Custom button text'
      const container = await createHelptext(`helptextDropdownButton="${buttonText}"`)

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      expect(helptext.helptextDropdownButton).toBe(buttonText)
    })
  })

  describe('Dropdown functionality', () => {
    test('does not render dropdown when no dropdown content', async () => {
      const container = await createHelptext('helptext="Regular helptext"')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const expandableContainer = helptext.querySelector('.pkt-inputwrapper__helptext-expandable')
      expect(expandableContainer).not.toBeInTheDocument()
    })

    test('renders dropdown when dropdown content is provided', async () => {
      const container = await createHelptext('helptextDropdown="Dropdown content"')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const expandableContainer = helptext.querySelector('.pkt-inputwrapper__helptext-expandable')
      expect(expandableContainer).toBeInTheDocument()

      const button = expandableContainer?.querySelector('button')
      expect(button).toBeInTheDocument()

      const expandableContent = expandableContainer?.querySelector(
        '.pkt-inputwrapper__helptext-expandable-closed',
      )
      expect(expandableContent).toBeInTheDocument()
    })

    test('toggles dropdown state on button click', async () => {
      const container = await createHelptext('helptextDropdown="Dropdown content"')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      expect(helptext.isHelpTextOpen).toBe(false)

      const button = helptext.querySelector('.pkt-inputwrapper__helptext-expandable button')
      expect(button).toBeInTheDocument()

      // Click to open
      fireEvent.click(button!)
      await helptext.updateComplete

      expect(helptext.isHelpTextOpen).toBe(true)

      const openContent = helptext.querySelector('.pkt-inputwrapper__helptext-expandable-open')
      expect(openContent).toBeInTheDocument()

      const closedContent = helptext.querySelector('.pkt-inputwrapper__helptext-expandable-closed')
      expect(closedContent).not.toBeInTheDocument()

      // Click to close
      fireEvent.click(button!)
      await helptext.updateComplete

      expect(helptext.isHelpTextOpen).toBe(false)
    })

    test('changes icon when dropdown is toggled', async () => {
      const container = await createHelptext('helptextDropdown="Dropdown content"')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const icon = helptext.querySelector('pkt-icon')
      expect(icon?.getAttribute('name')).toBe('chevron-thin-down')

      const button = helptext.querySelector('.pkt-inputwrapper__helptext-expandable button')
      fireEvent.click(button!)
      await helptext.updateComplete

      expect(icon?.getAttribute('name')).toBe('chevron-thin-up')
    })

    test('dispatches toggleHelpText event on dropdown toggle', async () => {
      const container = await createHelptext('helptextDropdown="Dropdown content"')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      let eventFired = false
      let eventDetail: any = null

      helptext.addEventListener('toggleHelpText', (e: Event) => {
        eventFired = true
        eventDetail = (e as CustomEvent).detail
      })

      const button = helptext.querySelector('.pkt-inputwrapper__helptext-expandable button')
      fireEvent.click(button!)

      expect(eventFired).toBe(true)
      expect(eventDetail).toEqual({ isOpen: true })
    })
  })

  describe('CSS classes and styling', () => {
    test('applies correct classes when no content', async () => {
      const container = await createHelptext()

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const helptextContainer = helptext.querySelector('.pkt-inputwrapper__helptext-container')
      expect(helptextContainer).toBeInTheDocument()
      expect(helptextContainer).not.toHaveClass('pkt-inputwrapper__has-helptext')
    })

    test('applies correct classes when helptext is provided', async () => {
      const container = await createHelptext('helptext="Some helptext"')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const helptextContainer = helptext.querySelector('.pkt-inputwrapper__helptext-container')
      expect(helptextContainer).toHaveClass('pkt-inputwrapper__has-helptext')
    })

    test('applies correct classes when dropdown is provided', async () => {
      const container = await createHelptext('helptextDropdown="Dropdown content"')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const helptextContainer = helptext.querySelector('.pkt-inputwrapper__helptext-container')
      expect(helptextContainer).toHaveClass('pkt-inputwrapper__has-helptext')
    })

    test('applies correct classes for closed dropdown', async () => {
      const container = await createHelptext('helptextDropdown="Dropdown content"')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const dropdownContent = helptext.querySelector(
        '.pkt-inputwrapper__helptext-expandable .pkt-inputwrapper__helptext',
      )
      expect(dropdownContent).toHaveClass('pkt-inputwrapper__helptext-expandable-closed')
      expect(dropdownContent).not.toHaveClass('pkt-inputwrapper__helptext-expandable-open')
    })

    test('applies correct classes for open dropdown', async () => {
      const container = await createHelptext('helptextDropdown="Dropdown content"')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const button = helptext.querySelector('.pkt-inputwrapper__helptext-expandable button')
      fireEvent.click(button!)
      await helptext.updateComplete

      const dropdownContent = helptext.querySelector(
        '.pkt-inputwrapper__helptext-expandable .pkt-inputwrapper__helptext',
      )
      expect(dropdownContent).toHaveClass('pkt-inputwrapper__helptext-expandable-open')
      expect(dropdownContent).not.toHaveClass('pkt-inputwrapper__helptext-expandable-closed')
    })
  })

  describe('Content rendering', () => {
    test('renders HTML content safely in helptext', async () => {
      const htmlContent = '<strong>Important</strong> information'
      const container = await createHelptext(`helptext="${htmlContent}"`)

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const strong = helptext.querySelector('strong')
      expect(strong).toBeInTheDocument()
      expect(strong?.textContent).toBe('Important')
    })

    test('renders HTML content safely in dropdown', async () => {
      const htmlContent = '<em>Emphasized</em> dropdown content'
      const container = await createHelptext(`helptextDropdown="${htmlContent}"`)

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const button = helptext.querySelector('.pkt-inputwrapper__helptext-expandable button')
      fireEvent.click(button!)
      await helptext.updateComplete

      const em = helptext.querySelector('em')
      expect(em).toBeInTheDocument()
      expect(em?.textContent).toBe('Emphasized')
    })

    test('renders both regular and dropdown content simultaneously', async () => {
      const regularContent = 'Regular helptext'
      const dropdownContent = 'Dropdown helptext'
      const container = await createHelptext(
        `helptext="${regularContent}" helptextDropdown="${dropdownContent}"`,
      )

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      expect(helptext.textContent).toContain(regularContent)

      const button = helptext.querySelector('.pkt-inputwrapper__helptext-expandable button')
      fireEvent.click(button!)
      await helptext.updateComplete

      expect(helptext.textContent).toContain(dropdownContent)
    })
  })

  describe('Slot management', () => {
    test('detects slot content via hasSlotContent()', async () => {
      const container = await createHelptext('', '<span>Slotted content</span>')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      expect(helptext.hasSlotContent()).toBe(true)
    })

    test('applies has-helptext class when slots are filled', async () => {
      const container = await createHelptext('', '<span>Slotted content</span>')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const helptextContainer = helptext.querySelector('.pkt-inputwrapper__helptext-container')
      expect(helptextContainer).toHaveClass('pkt-inputwrapper__has-helptext')
    })
  })

  describe('Accessibility', () => {
    test('basic helptext is accessible', async () => {
      const container = await createHelptext('helptext="Accessible helptext" forId="test-input"')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

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

      const helptextDiv = helptext.querySelector('.pkt-inputwrapper__helptext')
      expect(helptextDiv?.id).toBe('test-input-helptext')
    })

    test('dropdown helptext is accessible', async () => {
      const container = await createHelptext(
        'helptextDropdown="Dropdown content" helptextDropdownButton="Show more info"',
      )

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

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

      const button = helptext.querySelector('button')
      expect(button).toBeInTheDocument()
      expect(button?.type).toBe('button')
      expect(button?.textContent?.trim()).toContain('Show more info')
    })

    test('dropdown button has proper aria state', async () => {
      const container = await createHelptext('helptextDropdown="Dropdown content"')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      const button = helptext.querySelector('button')
      expect(button).toBeInTheDocument()

      // Button should be focusable and have proper role
      expect(button?.tagName).toBe('BUTTON')
      expect(button?.type).toBe('button')
    })
  })

  describe('Integration', () => {
    test('works with input wrapper context', async () => {
      const container = await createHelptext('forId="input-123" helptext="Field help information"')

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      // The ID should match what an input would use for aria-describedby
      const helptextDiv = helptext.querySelector('.pkt-inputwrapper__helptext')
      expect(helptextDiv?.id).toBe('input-123-helptext')
    })

    test('manages multiple content sources correctly', async () => {
      const container = await createHelptext(
        'helptext="Property text" helptextDropdown="Dropdown text"',
        '<span>Slot text</span>',
      )

      const helptext = container.querySelector('pkt-helptext') as PktHelptext
      await helptext.updateComplete

      // All content should be present but in correct locations
      expect(helptext.textContent).toContain('Property text')
      expect(helptext.textContent).toContain('Slot text')

      // Dropdown content should be present but hidden initially
      const dropdownContent = helptext.querySelector(
        '.pkt-inputwrapper__helptext-expandable-closed',
      )
      expect(dropdownContent).toBeInTheDocument()
      expect(dropdownContent?.textContent?.trim()).toContain('Dropdown text')
    })
  })
})
