import { mount } from '@vue/test-utils';
import VSelect from './VSelect.vue';
import { describe, it, expect } from 'vitest';

const testOptions = [
  { value: 'val1', label: 'Label 1' },
  { value: 'val2', label: 'Label 2', disabled: true },
  { value: 3, label: 'Label 3 (number)' }, // Numeric value
];

describe('VSelect.vue', () => {
  it('binds modelValue and emits update:modelValue correctly (v-model)', async () => {
    const wrapper = mount(VSelect, {
      props: { modelValue: 'val1', options: testOptions },
    });
    const selectElement = wrapper.find('select');

    // Check initial value
    expect(selectElement.element.value).toBe('val1');

    // Simulate user changing selection
    await selectElement.setValue('val2'); // This will select the option with value "val2"

    // Check emitted event
    expect(wrapper.emitted()['update:modelValue']).toBeTruthy();
    expect(wrapper.emitted()['update:modelValue'][0]).toEqual(['val2']);

    // Simulate parent v-model update
    await wrapper.setProps({ modelValue: 'val1' });
    expect(selectElement.element.value).toBe('val1');
  });

  it('correctly emits numeric value when a number option is selected', async () => {
    const wrapper = mount(VSelect, {
      props: { modelValue: '', options: testOptions, placeholder: 'Select...' },
    });
    const selectElement = wrapper.find('select');
    await selectElement.setValue('3'); // Value of 'Label 3 (number)' is 3 (a number)
    expect(wrapper.emitted()['update:modelValue'][0]).toEqual([3]); // Should emit the number 3
  });


  it('renders options correctly with labels, values, and disabled states', () => {
    const wrapper = mount(VSelect, {
      props: { modelValue: '', options: testOptions },
    });
    const optionElements = wrapper.findAll('option');
    expect(optionElements.length).toBe(testOptions.length);

    testOptions.forEach((opt, index) => {
      const optionElement = optionElements[index];
      expect(optionElement.attributes('value')).toBe(String(opt.value));
      expect(optionElement.text()).toBe(opt.label);
      if (opt.disabled) {
        expect(optionElement.attributes('disabled')).toBeDefined();
      } else {
        expect(optionElement.attributes('disabled')).toBeUndefined();
      }
    });
  });

  it('renders a placeholder option when placeholder prop is provided', () => {
    const placeholderText = 'Choose...';
    const wrapper = mount(VSelect, {
      props: { modelValue: '', options: testOptions, placeholder: placeholderText },
    });
    const placeholderOption = wrapper.find('option[value=""]');
    expect(placeholderOption.exists()).toBe(true);
    expect(placeholderOption.text()).toBe(placeholderText);
    expect(placeholderOption.attributes('disabled')).toBeDefined();
    // Check if it's selected when modelValue is empty
    expect(placeholderOption.element.selected).toBe(true);
  });

  it('placeholder is not selected if modelValue has a value', () => {
     const placeholderText = 'Choose...';
    const wrapper = mount(VSelect, {
      props: { modelValue: 'val1', options: testOptions, placeholder: placeholderText },
    });
    const placeholderOption = wrapper.find('option[value=""]');
    expect(placeholderOption.element.selected).toBe(false);
    const selectedVal1 = wrapper.find('option[value="val1"]');
    expect(selectedVal1.element.selected).toBe(true);
  });


  it('is disabled when disabled prop is true', () => {
    const wrapper = mount(VSelect, {
      props: { modelValue: '', options: testOptions, disabled: true },
    });
    expect(wrapper.find('select').attributes('disabled')).toBeDefined();
  });

  it('is required when required prop is true', () => {
    const wrapper = mount(VSelect, {
      props: { modelValue: '', options: testOptions, required: true },
    });
    expect(wrapper.find('select').attributes('required')).toBeDefined();
  });

  it('applies error class and aria-invalid when error prop is true', () => {
    const wrapper = mount(VSelect, {
      props: { modelValue: '', options: testOptions, error: true },
    });
    const select = wrapper.find('select');
    expect(select.classes()).toContain('form-input');
    expect(select.classes()).toContain('select');
    expect(select.classes()).toContain('error');
    expect(select.attributes('aria-invalid')).toBe('true');
  });

  it('does not apply error class or aria-invalid by default', () => {
    const wrapper = mount(VSelect, { props: { modelValue: '', options: testOptions } });
    const select = wrapper.find('select');
    expect(select.classes()).not.toContain('error');
    expect(select.attributes('aria-invalid')).toBeNull();
  });

  it('passes id prop to the select element', () => {
    const selectId = 'my-custom-select-id';
    const wrapper = mount(VSelect, {
      props: { modelValue: '', options: testOptions, id: selectId },
    });
    expect(wrapper.find('select').attributes('id')).toBe(selectId);
  });

  it('has "select" and "form-input" classes', () => {
     const wrapper = mount(VSelect, { props: { modelValue: '', options: testOptions } });
     expect(wrapper.find('select').classes()).toContain('select');
     expect(wrapper.find('select').classes()).toContain('form-input');
  });
});
