import BmsModal from '@/components/layout/BmsModal.vue';
import { mount, MountingOptions } from '@vue/test-utils';
import { describe, expect, it } from 'vitest';
import { inject, nextTick } from 'vue';

const BmsButtonStub = {
  template: `<div><slot /></div>`,
};

const intersectionObserverMock = () => ({
  observe: () => null,
});
window.IntersectionObserver = vi
  .fn()
  .mockImplementation(intersectionObserverMock);

const factory = (options: MountingOptions<any, {}> = {}) => {
  const wrapper = mount(BmsModal, {
    global: {
      stubs: {
        BmsButton: BmsButtonStub,
        teleport: true,
      },
    },
    slots: {
      default: 'Hello',
    },
    props: {
      title: 'MyModal',
      modelValue: false,
      backdropDismiss: true,
      closable: true,
      submitLabel: 'Valider',
      cancelLabel: 'Non!',
    },
    ...options,
  } as any);

  return {
    wrapper,
    openModal: async () => {
      await wrapper.setProps({
        modelValue: true,
      });
    },
  };
};

describe('BmsModal - provide', () => {
  it('provides bms-in-modal to child components', async () => {
    let injectedValue: boolean | undefined;
    const ChildComponent = {
      template: '<div />',
      setup() {
        injectedValue = inject('bms-in-modal', false);
      },
    };

    const { openModal } = factory({ slots: { default: ChildComponent } });
    await openModal();
    await nextTick();

    expect(injectedValue).toBe(true);
  });
});

describe('BmsModal', () => {
  it('should bind label', async () => {
    const { wrapper, openModal } = factory();

    await openModal();
    await nextTick();

    expect(wrapper.text()).toContain('MyModal');
    expect(wrapper.text()).toContain('Valider');
    expect(wrapper.text()).toContain('Non!');
  });

  it('should toggle modal', async () => {
    const { wrapper, openModal } = factory();

    await openModal();
    await nextTick();

    expect(wrapper.text()).toContain('Hello');
  });

  it('should close on X click', async () => {
    const { wrapper, openModal } = factory();

    await openModal();
    await nextTick();

    await wrapper.find('[data-testid="close-modal"]').trigger('click');
    await nextTick();

    expect(wrapper.emitted()['update:modelValue'][0]).toEqual([undefined]);
    await wrapper.setProps({ modelValue: false });

    await nextTick();

    expect(wrapper.text()).not.toContain('Hello');
  });

  it('should not close when not closable', async () => {
    const { wrapper, openModal } = factory();

    await wrapper.setProps({
      closable: false,
    });

    await openModal();
    await nextTick();

    await wrapper.find('[data-testid="close-modal"]').trigger('click');
    await nextTick();

    expect(wrapper.emitted()['update:modelValue']).not.toBeTruthy();
    expect(wrapper.text()).toContain('Hello');
  });

  it('should not close when in loading state', async () => {
    const { wrapper, openModal } = factory();

    await wrapper.setProps({
      closable: true,
      loading: true,
    });

    await openModal();
    await nextTick();

    await wrapper.find('[data-testid="close-modal"]').trigger('click');
    await nextTick();

    expect(wrapper.emitted()['update:modelValue']).not.toBeTruthy();
    expect(wrapper.text()).toContain('Hello');
  });

  describe('backdrop click handling', () => {
    it('should close when click on backdrop', async () => {
      const { wrapper, openModal } = factory();

      await openModal();
      await nextTick();

      (wrapper.vm as any).backdropClick();
      await nextTick();

      expect(wrapper.emitted()['update:modelValue'][0]).toEqual([undefined]);
      await wrapper.setProps({ modelValue: false });

      expect(wrapper.text()).not.toContain('Hello');
    });

    it('should not close when click on backdrop when not dismissable', async () => {
      const { wrapper, openModal } = factory();

      await wrapper.setProps({
        backdropDismiss: false,
      });

      await openModal();
      await nextTick();

      (wrapper.vm as any).backdropClick();
      await nextTick();

      expect(wrapper.emitted()['update:modelValue']).not.toBeTruthy();
      expect(wrapper.text()).toContain('Hello');
    });

    it('should not close when click on backdrop when in loading state', async () => {
      const { wrapper, openModal } = factory();

      await wrapper.setProps({
        closable: true,
        backdropDismiss: true,
        loading: true,
      });

      await openModal();
      await nextTick();

      await wrapper.find('[data-testid="backdrop-modal"]').trigger('click');
      await nextTick();

      expect(wrapper.emitted()['update:modelValue']).not.toBeTruthy();
      expect(wrapper.text()).toContain('Hello');
    });
  });
});
