import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import ToggleSwitch from '~/components/UI/ToggleSwitch.vue'

describe('ToggleSwitch', () => {
  describe('Rendering', () => {
    it('renders toggle switch', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
        },
      })

      expect(wrapper.find('button[role="switch"]').exists()).toBe(true)
    })

    it('renders with label when provided', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
          label: 'Enable Feature',
        },
      })

      expect(wrapper.text()).toContain('Enable Feature')
    })

    it('does not render label when not provided', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
        },
      })

      expect(wrapper.find('label').exists()).toBe(false)
    })
  })

  describe('States', () => {
    it('shows off state when modelValue is false', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
        },
      })

      const button = wrapper.find('button')
      expect(button.attributes('aria-checked')).toBe('false')
    })

    it('shows on state when modelValue is true', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: true,
        },
      })

      const button = wrapper.find('button')
      expect(button.attributes('aria-checked')).toBe('true')
    })

    it('applies green gradient when on', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: true,
        },
      })

      const track = wrapper.find('span[aria-hidden="true"]')
      expect(track.classes()).toContain('from-green-500')
    })

    it('applies gray background when off', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
        },
      })

      const track = wrapper.find('span[aria-hidden="true"]')
      expect(track.classes()).toContain('bg-gray-300')
    })
  })

  describe('Thumb Position', () => {
    it('positions thumb left when off', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
          size: 'md',
        },
      })

      const thumb = wrapper.findAll('span[aria-hidden="true"]')[1]
      expect(thumb.classes()).toContain('translate-x-0.5')
    })

    it('positions thumb right when on', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: true,
          size: 'md',
        },
      })

      const thumb = wrapper.findAll('span[aria-hidden="true"]')[1]
      expect(thumb.classes()).toContain('translate-x-5')
    })
  })

  describe('Sizes', () => {
    it('applies small size classes', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
          size: 'sm',
        },
      })

      const button = wrapper.find('button')
      expect(button.classes()).toContain('h-5')
      expect(button.classes()).toContain('w-9')
    })

    it('applies medium size classes', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
          size: 'md',
        },
      })

      const button = wrapper.find('button')
      expect(button.classes()).toContain('h-6')
      expect(button.classes()).toContain('w-11')
    })

    it('applies large size classes', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
          size: 'lg',
        },
      })

      const button = wrapper.find('button')
      expect(button.classes()).toContain('h-7')
      expect(button.classes()).toContain('w-14')
    })
  })

  describe('Interactions', () => {
    it('emits update:modelValue with true when clicked while off', async () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
        },
      })

      await wrapper.find('button').trigger('click')
      expect(wrapper.emitted('update:modelValue')).toBeTruthy()
      expect(wrapper.emitted('update:modelValue')![0]).toEqual([true])
    })

    it('emits update:modelValue with false when clicked while on', async () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: true,
        },
      })

      await wrapper.find('button').trigger('click')
      expect(wrapper.emitted('update:modelValue')).toBeTruthy()
      expect(wrapper.emitted('update:modelValue')![0]).toEqual([false])
    })

    it('clicking label toggles switch', async () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
          label: 'Test Label',
        },
      })

      await wrapper.find('label').trigger('click')
      expect(wrapper.emitted('update:modelValue')).toBeTruthy()
      expect(wrapper.emitted('update:modelValue')![0]).toEqual([true])
    })
  })

  describe('Disabled State', () => {
    it('disables button when disabled prop is true', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
          disabled: true,
        },
      })

      expect(wrapper.find('button').attributes('disabled')).toBe('')
    })

    it('does not emit when disabled', async () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
          disabled: true,
        },
      })

      await wrapper.find('button').trigger('click')
      expect(wrapper.emitted('update:modelValue')).toBeFalsy()
    })

    it('applies disabled styles to button', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
          disabled: true,
        },
      })

      const button = wrapper.find('button')
      expect(button.classes()).toContain('disabled:opacity-50')
      expect(button.classes()).toContain('disabled:cursor-not-allowed')
    })

    it('applies disabled styles to label', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
          disabled: true,
          label: 'Test',
        },
      })

      const label = wrapper.find('label')
      expect(label.classes()).toContain('text-gray-400')
      expect(label.classes()).toContain('cursor-not-allowed')
    })
  })

  describe('Accessibility', () => {
    it('has correct role attribute', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
        },
      })

      expect(wrapper.find('button').attributes('role')).toBe('switch')
    })

    it('has correct aria-checked attribute', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: true,
        },
      })

      expect(wrapper.find('button').attributes('aria-checked')).toBe('true')
    })

    it('updates aria-checked when value changes', async () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
        },
      })

      await wrapper.setProps({ modelValue: true })
      expect(wrapper.find('button').attributes('aria-checked')).toBe('true')
    })

    it('inner elements have aria-hidden', () => {
      const wrapper = mount(ToggleSwitch, {
        props: {
          modelValue: false,
        },
      })

      const innerElements = wrapper.findAll('span[aria-hidden="true"]')
      expect(innerElements.length).toBeGreaterThan(0)
    })
  })
})
