import { mount } from '@vue/test-utils'
import { CStepper as Component } from '../../../index'

const ComponentName = 'CStepper'

const stepsMock = [
  { label: 'Step 1', content: 'Content 1' },
  { label: 'Step 2', content: 'Content 2' },
  { label: 'Step 3', content: 'Content 3' },
]

const defaultWrapper = mount(Component, {
  propsData: {
    steps: stepsMock,
  },
})

const verticalWrapper = mount(Component, {
  propsData: {
    steps: stepsMock,
    layout: 'vertical',
  },
})

const linearWrapper = mount(Component, {
  propsData: {
    steps: stepsMock,
    linear: true,
  },
})

describe(`Loads and display ${ComponentName} component`, () => {
  it('has a name', () => {
    expect(Component.name).toMatch(ComponentName)
  })

  it('renders correctly', () => {
    expect(defaultWrapper.html()).toMatchSnapshot()
  })

  it('contains step labels and content', () => {
    expect(defaultWrapper.text()).toContain('Step 1')
    expect(defaultWrapper.text()).toContain('Content 1')
  })
})

describe(`Vertical layout ${ComponentName} component`, () => {
  it('renders correctly', () => {
    expect(verticalWrapper.html()).toMatchSnapshot()
  })

  it('uses vertical layout class (if applicable)', () => {
    expect(verticalWrapper.classes()).toContain('stepper-vertical') // optional
  })
})

describe(`Linear mode ${ComponentName} component`, () => {
  it('disables future steps', () => {
    const tabs = linearWrapper.findAll('[role="tab"]')
    expect(tabs[0].attributes('disabled')).toBeUndefined()
    expect(tabs[1].attributes('disabled')).toBeDefined()
    expect(tabs[2].attributes('disabled')).toBeDefined()
  })
})

describe(`Non-linear mode ${ComponentName} component`, () => {
  const wrapper = mount(Component, {
    propsData: {
      steps: stepsMock,
      linear: false,
    },
  })

  it('allows clicking all steps', () => {
    const tabs = wrapper.findAll('[role="tab"]')
    expect(tabs[0].attributes('disabled')).toBeUndefined()
    expect(tabs[1].attributes('disabled')).toBeUndefined()
    expect(tabs[2].attributes('disabled')).toBeUndefined()
  })

  it('calls onStepChange when step is clicked', async () => {
    const onStepChange = jest.fn()
    const customWrapper = mount(Component, {
      propsData: {
        steps: stepsMock,
        linear: false,
        onStepChange,
      },
    })
    await customWrapper.findAll('[role="tab"]')[2].trigger('click')
    expect(onStepChange).toHaveBeenCalledWith(3)
  })
})

describe(`Active step content ${ComponentName}`, () => {
  const wrapper = mount(Component, {
    propsData: {
      steps: stepsMock,
      layout: 'horizontal',
      modelValue: 1,
    },
  })

  it('renders only first step content', () => {
    expect(wrapper.text()).toContain('Content 1')
    expect(wrapper.text()).not.toContain('Content 2')
    expect(wrapper.text()).not.toContain('Content 3')
  })
})

describe(`Finish and reset events ${ComponentName}`, () => {
  it('calls onFinish when last step is clicked', async () => {
    const onFinish = jest.fn()
    const wrapper = mount(Component, {
      propsData: {
        steps: stepsMock,
        onFinish,
        linear: false,
        modelValue: 3,
      },
    })

    await wrapper.findAll('[role="tab"]')[2].trigger('click')
    expect(onFinish).toHaveBeenCalledTimes(1)
  })

  it('resets and focuses first step', async () => {
    const onReset = jest.fn()
    const wrapper = mount(Component, {
      propsData: {
        steps: stepsMock,
        onReset,
      },
    })

    const instance = wrapper.vm as any
    instance.next()
    await wrapper.vm.$nextTick()
    instance.reset()
    await wrapper.vm.$nextTick()

    expect(onReset).toHaveBeenCalled()
    expect(wrapper.findAll('[role="tab"]')[0].element).toBe(document.activeElement)
  })
})

describe(`Uncontrolled vs Controlled ${ComponentName}`, () => {
  it('starts at defaultActiveStepNumber', () => {
    const wrapper = mount(Component, {
      propsData: {
        steps: stepsMock,
        defaultActiveStepNumber: 2,
      },
    })

    expect(wrapper.text()).toContain('Content 2')
    expect(wrapper.text()).not.toContain('Content 1')
  })

  it('reacts to modelValue change', async () => {
    const wrapper = mount(Component, {
      propsData: {
        steps: stepsMock,
        modelValue: 1,
      },
    })

    expect(wrapper.text()).toContain('Content 1')

    await wrapper.setProps({ modelValue: 3 })

    expect(wrapper.text()).toContain('Content 3')
    expect(wrapper.text()).not.toContain('Content 1')
  })
})
