import '@testing-library/jest-dom'
import { axe, toHaveNoViolations } from 'jest-axe'
import { fireEvent } from '@testing-library/dom'
import { vi } from 'vitest'
import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
import { CustomElementFor } from '../../tests/component-registry'
import { type IPktMessagebox } from './messagebox'
import './messagebox'

export interface MessageboxTestConfig extends Partial<IPktMessagebox>, BaseTestConfig {}

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

  return {
    container,
    messagebox: element,
  }
}

expect.extend(toHaveNoViolations)

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

describe('PktMessagebox', () => {
  describe('Rendering and basic functionality', () => {
    test('renders without errors', async () => {
      const { messagebox } = await createMessageboxTest()

      expect(messagebox).toBeInTheDocument()
      expect(messagebox).toBeTruthy()
    })

    test('renders with basic structure', async () => {
      const { messagebox } = await createMessageboxTest({
        title: 'Test Title',
        content: 'Test content',
      })

      const messageboxDiv = messagebox.querySelector('.pkt-messagebox')
      expect(messageboxDiv).toBeInTheDocument()

      const title = messagebox.querySelector('.pkt-messagebox__title')
      expect(title).toBeInTheDocument()
      expect(title?.textContent).toBe('Test Title')

      const text = messagebox.querySelector('.pkt-messagebox__text')
      expect(text).toBeInTheDocument()
    })

    test('renders content correctly', async () => {
      const { messagebox } = await createMessageboxTest({
        content: 'This is the message content',
      })

      const text = messagebox.querySelector('.pkt-messagebox__text')
      expect(text?.textContent).toContain('This is the message content')
    })
  })

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

      expect(messagebox.closable).toBe(false)
      expect(messagebox.compact).toBe(false)
      expect(messagebox.title).toBe('')
      expect(messagebox.skin).toBe('beige')
    })

    test('sets properties correctly', async () => {
      const { messagebox } = await createMessageboxTest({
        closable: true,
        compact: true,
        title: 'Custom Title',
        skin: 'blue',
      })

      expect(messagebox.closable).toBe(true)
      expect(messagebox.compact).toBe(true)
      expect(messagebox.title).toBe('Custom Title')
      expect(messagebox.skin).toBe('blue')
    })
  })

  describe('Skin variants', () => {
    test('applies beige skin correctly', async () => {
      const { messagebox } = await createMessageboxTest({ skin: 'beige' })

      const messageboxDiv = messagebox.querySelector('.pkt-messagebox')
      expect(messageboxDiv?.classList.contains('pkt-messagebox--beige')).toBe(true)
    })

    test('applies blue skin correctly', async () => {
      const { messagebox } = await createMessageboxTest({ skin: 'blue' })

      const messageboxDiv = messagebox.querySelector('.pkt-messagebox')
      expect(messageboxDiv?.classList.contains('pkt-messagebox--blue')).toBe(true)
    })

    test('applies red skin correctly', async () => {
      const { messagebox } = await createMessageboxTest({ skin: 'red' })

      const messageboxDiv = messagebox.querySelector('.pkt-messagebox')
      expect(messageboxDiv?.classList.contains('pkt-messagebox--red')).toBe(true)
    })

    test('applies green skin correctly', async () => {
      const { messagebox } = await createMessageboxTest({ skin: 'green' })

      const messageboxDiv = messagebox.querySelector('.pkt-messagebox')
      expect(messageboxDiv?.classList.contains('pkt-messagebox--green')).toBe(true)
    })
  })

  describe('Compact mode', () => {
    test('applies compact class when compact is true', async () => {
      const { messagebox } = await createMessageboxTest({ compact: true })

      const messageboxDiv = messagebox.querySelector('.pkt-messagebox')
      expect(messageboxDiv?.classList.contains('pkt-messagebox--compact')).toBe(true)
    })

    test('does not apply compact class when compact is false', async () => {
      const { messagebox } = await createMessageboxTest({ compact: false })

      const messageboxDiv = messagebox.querySelector('.pkt-messagebox')
      expect(messageboxDiv?.classList.contains('pkt-messagebox--compact')).toBe(false)
    })
  })

  describe('Closable functionality', () => {
    test('renders close button when closable is true', async () => {
      const { messagebox } = await createMessageboxTest({ closable: true })

      const closeButton = messagebox.querySelector('.pkt-messagebox__close button')
      expect(closeButton).toBeInTheDocument()

      const closeIcon = messagebox.querySelector('pkt-icon[name="close"]')
      expect(closeIcon).toBeInTheDocument()
    })

    test('does not render close button when closable is false', async () => {
      const { messagebox } = await createMessageboxTest({ closable: false })

      const closeButton = messagebox.querySelector('.pkt-messagebox__close')
      expect(closeButton).not.toBeInTheDocument()
    })

    test('closes messagebox when close button is clicked', async () => {
      const { messagebox } = await createMessageboxTest({ closable: true })

      const closeButton = messagebox.querySelector('.pkt-messagebox__close button')
      fireEvent.click(closeButton!)

      await messagebox.updateComplete
      expect(messagebox._isClosed).toBe(true)
      expect(messagebox.classList.contains('pkt-hide')).toBe(true)
    })

    test('dispatches close events when closed', async () => {
      const { messagebox } = await createMessageboxTest({ closable: true })

      const closeHandler = vi.fn()
      const onCloseHandler = vi.fn()
      messagebox.addEventListener('close', closeHandler)
      messagebox.addEventListener('on-close', onCloseHandler)

      const closeButton = messagebox.querySelector('.pkt-messagebox__close button')
      fireEvent.click(closeButton!)

      expect(closeHandler).toHaveBeenCalled()
      expect(onCloseHandler).toHaveBeenCalled()
    })
  })

  describe('Title functionality', () => {
    test('renders title when provided', async () => {
      const { messagebox } = await createMessageboxTest({ title: 'Important Message' })

      const title = messagebox.querySelector('.pkt-messagebox__title')
      expect(title).toBeInTheDocument()
      expect(title?.textContent).toBe('Important Message')
      expect(title?.textContent).toBe('Important Message')
    })

    test('does not render title when empty', async () => {
      const { messagebox } = await createMessageboxTest({ title: '' })

      const title = messagebox.querySelector('.pkt-messagebox__title')
      expect(title).not.toBeInTheDocument()
    })
  })

  describe('CSS classes', () => {
    test('applies base messagebox class', async () => {
      const { messagebox } = await createMessageboxTest()

      const messageboxDiv = messagebox.querySelector('.pkt-messagebox')
      expect(messageboxDiv?.classList.contains('pkt-messagebox')).toBe(true)
    })

    test('applies closable class when closable', async () => {
      const { messagebox } = await createMessageboxTest({ closable: true })

      const messageboxDiv = messagebox.querySelector('.pkt-messagebox')
      expect(messageboxDiv?.classList.contains('pkt-messagebox--closable')).toBe(true)
    })
  })

  describe('Accessibility', () => {
    test('basic messagebox is accessible', async () => {
      const { container } = await createMessageboxTest({
        title: 'Accessible Message',
        content: 'This is an accessible message',
      })
      await new Promise((resolve) => setTimeout(resolve, 100))

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

    test('closable messagebox is accessible', async () => {
      const { container } = await createMessageboxTest({
        closable: true,
        title: 'Closable Message',
        content: 'This message can be closed',
      })
      await new Promise((resolve) => setTimeout(resolve, 100))

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