import { field } from '@/plugins/field';
import BmsInputText, { type Props } from './BmsInputText.vue';
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';

const factory = (props: Props) => {
  const wrapper = mount(BmsInputText, { props, global: { plugins: [field] } });
  const inputElement = wrapper.get('input');

  return { wrapper, inputElement };
};

describe('BmsInputText', () => {
  it('should display correct value on init', () => {
    const { inputElement } = factory({ modelValue: 'toto' });

    expect(inputElement.element.value).toStrictEqual('toto');
  });

  it('should react correctly on input', async () => {
    const { wrapper, inputElement } = factory({ modelValue: 'toto' });

    inputElement.setValue('titi');
    await nextTick();
    expect(wrapper.emitted()['update:modelValue'][0]).toStrictEqual(['titi']);
  });

  it('should not update if disabled', async () => {
    const { wrapper, inputElement } = factory({
      modelValue: 'toto',
      disabled: true,
    });

    inputElement.setValue('titi');
    await nextTick();
    expect(wrapper.emitted()['update:modelValue']).toBeUndefined();
  });

  it('should try limit of the input when value change', async () => {
    const { wrapper, inputElement } = factory({
      modelValue: 'toto',
      disabled: true,
      maxlength: 5,
      minlength: 2,
    });

    expect((wrapper.vm as any).computedErrors.length).toBe(0);
    await wrapper.setProps({ modelValue: 'superToto' });
    await nextTick();

    expect((wrapper.vm as any).computedErrors.length).toBe(1);
    expect((wrapper.vm as any).computedErrors[0]).toBe(
      'Longueur supérieure au maximum autorisé (max:5)',
    );
    await wrapper.setProps({ modelValue: 't' });
    await nextTick();

    expect((wrapper.vm as any).computedErrors.length).toBe(1);
    expect((wrapper.vm as any).computedErrors[0]).toBe(
      'Longueur inférieur au minimum autorisé (min:2)',
    );
  });

  it('should emit blur event for form validation', async () => {
    const { wrapper, inputElement } = factory({
      modelValue: 'toto',
      disabled: true,
    });

    inputElement.setValue('titi');
    await nextTick();
    expect(wrapper.emitted()['update:modelValue']).toBeUndefined();
  });

  describe('checkPattern', () => {
    it('should not add error when value matches pattern', async () => {
      const { wrapper } = factory({
        modelValue: 'abc123',
        pattern: '^[a-z0-9]+$',
      });

      await nextTick();
      expect((wrapper.vm as any).computedErrors.length).toBe(0);
    });

    it('should add error when value does not match pattern', async () => {
      const { wrapper } = factory({
        modelValue: 'ABC!!!',
        pattern: '^[a-z0-9]+$',
      });

      await nextTick();
      expect((wrapper.vm as any).computedErrors.length).toBe(1);
      expect((wrapper.vm as any).computedErrors[0]).toBe(
        'La valeur ne correspond pas au motif attendu ( ^[a-z0-9]+$ )',
      );
    });

    it('should use custom patternMessage when provided', async () => {
      const { wrapper } = factory({
        modelValue: 'ABC!!!',
        pattern: '^[a-z0-9]+$',
        patternMessage: 'Format invalide',
      });

      await nextTick();
      expect((wrapper.vm as any).computedErrors.length).toBe(1);
      expect((wrapper.vm as any).computedErrors[0]).toBe('Format invalide');
    });

    it('should not add error when pattern is empty', async () => {
      const { wrapper } = factory({
        modelValue: 'anything',
        pattern: '',
      });

      await nextTick();
      expect((wrapper.vm as any).computedErrors.length).toBe(0);
    });

    it('should not add error when value matches RegExp pattern', async () => {
      const { wrapper } = factory({
        modelValue: 'abc123',
        pattern: /^[a-z0-9]+$/,
      });

      await nextTick();
      expect((wrapper.vm as any).internalErrors.length).toBe(0);
    });

    it('should add error when value does not match RegExp pattern', async () => {
      const { wrapper } = factory({
        modelValue: 'ABC!!!',
        pattern: /^[a-z0-9]+$/,
      });

      await nextTick();
      expect((wrapper.vm as any).internalErrors.length).toBe(1);
    });

    it('should check pattern on blur', async () => {
      const { wrapper, inputElement } = factory({
        modelValue: 'valid',
        pattern: '^[a-z]+$',
      });

      await nextTick();
      expect((wrapper.vm as any).computedErrors.length).toBe(0);

      await wrapper.setProps({ modelValue: '123' });
      await nextTick();
      // watch only calls checkLimit, not checkPattern
      expect((wrapper.vm as any).computedErrors.length).toBe(0);

      await inputElement.trigger('blur');
      await nextTick();
      expect((wrapper.vm as any).computedErrors.length).toBe(1);
      expect((wrapper.vm as any).computedErrors[0]).toBe(
        'La valeur ne correspond pas au motif attendu ( ^[a-z]+$ )',
      );
    });
  });
});
