import { shallowMount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui';
import INVALID_URL from '~/lib/utils/invalid_url';
import AlertWidgetForm from '~/monitoring/components/alert_widget_form.vue';
import ModalStub from '../stubs/modal_stub';

describe('AlertWidgetForm', () => {
  let wrapper;

  const metricId = '8';
  const alertPath = 'alert';
  const relevantQueries = [{ metricId, alert_path: alertPath, label: 'alert-label' }];
  const dataTrackingOptions = {
    create: { action: 'click_button', label: 'create_alert' },
    delete: { action: 'click_button', label: 'delete_alert' },
    update: { action: 'click_button', label: 'update_alert' },
  };

  const defaultProps = {
    disabled: false,
    relevantQueries,
    modalId: 'alert-modal-1',
  };

  const propsWithAlertData = {
    ...defaultProps,
    alertsToManage: {
      alert: {
        alert_path: alertPath,
        operator: '<',
        threshold: 5,
        metricId,
        runbookUrl: INVALID_URL,
      },
    },
    configuredAlert: metricId,
  };

  function createComponent(props = {}) {
    const propsData = {
      ...defaultProps,
      ...props,
    };

    wrapper = shallowMount(AlertWidgetForm, {
      propsData,
      stubs: {
        GlModal: ModalStub,
      },
    });
  }

  const modal = () => wrapper.find(ModalStub);
  const modalTitle = () => modal().attributes('title');
  const submitButton = () => modal().find(GlLink);
  const findRunbookField = () => modal().find('[data-testid="alertRunbookField"]');
  const findThresholdField = () => modal().find('[data-qa-selector="alert_threshold_field"]');
  const submitButtonTrackingOpts = () =>
    JSON.parse(submitButton().attributes('data-tracking-options'));
  const stubEvent = { preventDefault: jest.fn() };

  afterEach(() => {
    if (wrapper) wrapper.destroy();
  });

  it('disables the form when disabled prop is set', () => {
    createComponent({ disabled: true });

    expect(modal().attributes('ok-disabled')).toBe('true');
  });

  it('disables the form if no query is selected', () => {
    createComponent();

    expect(modal().attributes('ok-disabled')).toBe('true');
  });

  it('shows correct title and button text', () => {
    createComponent();

    expect(modalTitle()).toBe('Add alert');
    expect(submitButton().text()).toBe('Add');
  });

  it('sets tracking options for create alert', () => {
    createComponent();

    expect(submitButtonTrackingOpts()).toEqual(dataTrackingOptions.create);
  });

  it('emits a "create" event when form submitted without existing alert', async () => {
    createComponent(defaultProps);

    modal().vm.$emit('shown');

    findThresholdField().vm.$emit('input', 900);
    findRunbookField().vm.$emit('input', INVALID_URL);

    modal().vm.$emit('ok', stubEvent);

    expect(wrapper.emitted().create[0]).toEqual([
      {
        alert: undefined,
        operator: '>',
        threshold: 900,
        prometheus_metric_id: '8',
        runbookUrl: INVALID_URL,
      },
    ]);
  });

  it('resets form when modal is dismissed (hidden)', () => {
    createComponent(defaultProps);

    modal().vm.$emit('shown');

    findThresholdField().vm.$emit('input', 800);
    findRunbookField().vm.$emit('input', INVALID_URL);

    modal().vm.$emit('hidden');

    expect(wrapper.vm.selectedAlert).toEqual({});
    expect(wrapper.vm.operator).toBe(null);
    expect(wrapper.vm.threshold).toBe(null);
    expect(wrapper.vm.prometheusMetricId).toBe(null);
    expect(wrapper.vm.runbookUrl).toBe(null);
  });

  it('sets selectedAlert to the provided configuredAlert on modal show', () => {
    createComponent(propsWithAlertData);

    modal().vm.$emit('shown');

    expect(wrapper.vm.selectedAlert).toEqual(propsWithAlertData.alertsToManage[alertPath]);
  });

  it('sets selectedAlert to the first relevantQueries if there is only one option on modal show', () => {
    createComponent({
      ...propsWithAlertData,
      configuredAlert: '',
    });

    modal().vm.$emit('shown');

    expect(wrapper.vm.selectedAlert).toEqual(propsWithAlertData.alertsToManage[alertPath]);
  });

  it('does not set selectedAlert to the first relevantQueries if there is more than one option on modal show', () => {
    createComponent({
      relevantQueries: [
        {
          metricId: '8',
          alertPath: 'alert',
          label: 'alert-label',
        },
        {
          metricId: '9',
          alertPath: 'alert',
          label: 'alert-label',
        },
      ],
    });

    modal().vm.$emit('shown');

    expect(wrapper.vm.selectedAlert).toEqual({});
  });

  describe('with existing alert', () => {
    beforeEach(() => {
      createComponent(propsWithAlertData);

      modal().vm.$emit('shown');
    });

    it('sets tracking options for delete alert', () => {
      expect(submitButtonTrackingOpts()).toEqual(dataTrackingOptions.delete);
    });

    it('updates button text', () => {
      expect(modalTitle()).toBe('Edit alert');
      expect(submitButton().text()).toBe('Delete');
    });

    it('emits "delete" event when form values unchanged', () => {
      modal().vm.$emit('ok', stubEvent);

      expect(wrapper.emitted().delete[0]).toEqual([
        {
          alert: 'alert',
          operator: '<',
          threshold: 5,
          prometheus_metric_id: '8',
          runbookUrl: INVALID_URL,
        },
      ]);
    });
  });

  it('emits "update" event when form changed', () => {
    const updatedRunbookUrl = `${INVALID_URL}/test`;

    createComponent(propsWithAlertData);

    modal().vm.$emit('shown');

    findRunbookField().vm.$emit('input', updatedRunbookUrl);
    findThresholdField().vm.$emit('input', 11);

    modal().vm.$emit('ok', stubEvent);

    expect(wrapper.emitted().update[0]).toEqual([
      {
        alert: 'alert',
        operator: '<',
        threshold: 11,
        prometheus_metric_id: '8',
        runbookUrl: updatedRunbookUrl,
      },
    ]);
  });

  it('sets tracking options for update alert', async () => {
    createComponent(propsWithAlertData);

    modal().vm.$emit('shown');

    findThresholdField().vm.$emit('input', 11);

    await wrapper.vm.$nextTick();

    expect(submitButtonTrackingOpts()).toEqual(dataTrackingOptions.update);
  });

  describe('alert runbooks', () => {
    it('shows the runbook field', () => {
      createComponent();

      expect(findRunbookField().exists()).toBe(true);
    });
  });
});
