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 { type IPktProgressbar } from './progressbar'
import './progressbar'

export interface ProgressbarTestConfig extends Partial<IPktProgressbar>, BaseTestConfig {}

export const createProgressbarTest = async (config: ProgressbarTestConfig = {}) => {
  const { container, element } = await createElementTest<
    CustomElementFor<'pkt-progressbar'>,
    ProgressbarTestConfig
  >('pkt-progressbar', config)

  return {
    container,
    progressbar: element,
  }
}

expect.extend(toHaveNoViolations)

afterEach(() => {
  document.body.innerHTML = ''
})

describe('PktProgressbar', () => {
  describe('Rendering and basic functionality', () => {
    test('renders without errors', async () => {
      const { progressbar } = await createProgressbarTest()

      expect(progressbar).toBeInTheDocument()
      expect(progressbar).toBeTruthy()
    })

    test('renders with progress value', async () => {
      const { progressbar } = await createProgressbarTest({ valueCurrent: 50 })

      expect(progressbar.valueCurrent).toBe(50)
      expect(progressbar.getAttribute('role')).toBe('progressbar')
    })
  })

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

      expect(progressbar.valueCurrent).toBe(0)
      expect(progressbar.valueMin).toBe(0)
      expect(progressbar.valueMax).toBe(100)
      expect(progressbar.skin).toBe('dark-blue')
      expect(progressbar.role).toBe('progressbar')
    })

    test('sets properties correctly', async () => {
      const { progressbar } = await createProgressbarTest({
        valueCurrent: 75,
        valueMin: 10,
        valueMax: 200,
        skin: 'green',
        title: 'Loading',
      })

      expect(progressbar.valueCurrent).toBe(75)
      expect(progressbar.valueMin).toBe(10)
      expect(progressbar.valueMax).toBe(200)
      expect(progressbar.skin).toBe('green')
      expect(progressbar.title).toBe('Loading')
    })
  })

  describe('Skin variants', () => {
    test('applies dark-blue skin correctly', async () => {
      const { progressbar } = await createProgressbarTest({ skin: 'dark-blue' })

      const barElement = progressbar.querySelector('.pkt-progressbar__bar')
      expect(barElement?.classList.contains('pkt-progressbar__bar--dark-blue')).toBe(true)
    })

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

      const barElement = progressbar.querySelector('.pkt-progressbar__bar')
      expect(barElement?.classList.contains('pkt-progressbar__bar--green')).toBe(true)
    })

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

      const barElement = progressbar.querySelector('.pkt-progressbar__bar')
      expect(barElement?.classList.contains('pkt-progressbar__bar--red')).toBe(true)
    })
  })

  describe('Status display', () => {
    test('shows percentage when statusType is percentage', async () => {
      const { progressbar } = await createProgressbarTest({
        valueCurrent: 50,
        statusType: 'percentage',
      })

      const statusElement = progressbar.querySelector('.pkt-progressbar__status')
      expect(statusElement?.textContent).toContain('50%')
    })

    test('shows fraction when statusType is fraction', async () => {
      const { progressbar } = await createProgressbarTest({
        valueCurrent: 25,
        valueMax: 50,
        statusType: 'fraction',
      })

      const statusElement = progressbar.querySelector('.pkt-progressbar__status')
      expect(statusElement?.textContent?.trim()).toContain('25 av 50')
    })

    test('hides status when statusType is none', async () => {
      const { progressbar } = await createProgressbarTest({
        valueCurrent: 50,
        statusType: 'none',
      })

      const statusElement = progressbar.querySelector('.pkt-progressbar__status')
      expect(statusElement).not.toBeInTheDocument()
    })
  })

  describe('Title functionality', () => {
    test('renders title when provided', async () => {
      const { progressbar } = await createProgressbarTest({ title: 'Loading progress' })

      const titleElement = progressbar.querySelector('.pkt-progressbar__title')
      expect(titleElement).toBeInTheDocument()
      expect(titleElement?.textContent).toBe('Loading progress')
    })

    test('does not render title when empty', async () => {
      const { progressbar } = await createProgressbarTest()

      const titleElement = progressbar.querySelector('.pkt-progressbar__title')
      expect(titleElement).not.toBeInTheDocument()
    })
  })

  describe('ARIA and accessibility', () => {
    test('has correct ARIA attributes', async () => {
      const { progressbar } = await createProgressbarTest({
        valueCurrent: 60,
        ariaLabel: 'File upload progress',
      })

      expect(progressbar.getAttribute('aria-valuemin')).toBe('0')
      expect(progressbar.getAttribute('aria-valuemax')).toBe('100')
      expect(progressbar.getAttribute('aria-valuenow')).toBe('60')
      expect(progressbar.getAttribute('aria-label')).toBe('File upload progress')
    })

    test('updates aria-valuenow when value changes', async () => {
      const { progressbar } = await createProgressbarTest({ valueCurrent: 30 })

      progressbar.valueCurrent = 80
      await progressbar.updateComplete

      expect(progressbar.getAttribute('aria-valuenow')).toBe('80')
    })
  })

  describe('Role variants', () => {
    test('uses progressbar role by default', async () => {
      const { progressbar } = await createProgressbarTest()

      expect(progressbar.getAttribute('role')).toBe('progressbar')
    })

    test('uses meter role when specified', async () => {
      const { progressbar } = await createProgressbarTest({ role: 'meter' })

      expect(progressbar.getAttribute('role')).toBe('meter')
    })
  })

  describe('Accessibility', () => {
    test('progressbar is accessible', async () => {
      const { container } = await createProgressbarTest({
        title: 'Upload progress',
        valueCurrent: 50,
        ariaLabel: 'File upload progress',
      })

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