import Vuex from 'vuex';
import { mount, createLocalVue } from '@vue/test-utils';

import { GlSparklineChart } from '@gitlab/ui/dist/charts';

import stubChildren from 'helpers/stub_children';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import Chart from 'ee/security_dashboard/components/vulnerability_chart.vue';
import ChartButtons from 'ee/security_dashboard/components/vulnerability_chart_buttons.vue';

const localVue = createLocalVue();
localVue.use(Vuex);

describe('Vulnerability Chart component', () => {
  let actions;
  let getters;
  let state;
  let store;
  let wrapper;

  const findTimeInfo = () => wrapper.find({ ref: 'timeInfo' });
  const findSeverityBadgeForLevel = severityLevel =>
    wrapper.find(SeverityBadge, { ref: `severityBadge${severityLevel}` });
  const findSparklineChartForLevel = severityLevel =>
    wrapper.find(GlSparklineChart, { ref: `sparklineChart${severityLevel}` });
  const findChangeInPercent = () => wrapper.find({ ref: 'changeInPercent' });
  const findCurrentVulnerabilitiesCount = () =>
    wrapper.find({ ref: 'currentVulnerabilitiesCount' });

  const factory = ({ vulnerabilitiesCount = [], stubs = {} } = {}) => {
    actions = {
      setVulnerabilitiesHistoryDayRange: jest.fn(),
    };

    getters = {
      getFilteredVulnerabilitiesHistory: () => () =>
        vulnerabilitiesCount.map(c => ['some-date', c]),
      getVulnerabilityHistoryByName: () => () => [],
    };

    state = {
      vulnerabilitiesHistory: {},
      vulnerabilitiesHistoryDayRange: 90,
      vulnerabilitiesHistoryMaxDayInterval: 7,
    };

    store = new Vuex.Store({
      modules: {
        vulnerabilities: {
          namespaced: true,
          actions,
          getters,
          state,
        },
      },
    });

    wrapper = mount(Chart, {
      localVue,
      store,
      stubs: {
        ...stubChildren(Chart),
        ...stubs,
      },
    });
  };

  afterEach(() => {
    wrapper.destroy();
    jest.restoreAllMocks();
  });

  describe('header', () => {
    it.each`
      mockDate                  | dayRange | expectedStartDate
      ${'2000-01-01T00:00:00Z'} | ${90}    | ${'October 3rd'}
      ${'2000-01-01T00:00:00Z'} | ${60}    | ${'November 2nd'}
      ${'2000-01-01T00:00:00Z'} | ${30}    | ${'December 2nd'}
    `(
      'shows "$expectedStartDate" when the date range is set to "$dayRange" days',
      ({ mockDate, dayRange, expectedStartDate }) => {
        jest.spyOn(global.Date, 'now').mockImplementation(() => new Date(mockDate));

        factory();

        store.state.vulnerabilities.vulnerabilitiesHistoryDayRange = dayRange;

        return wrapper.vm.$nextTick().then(() => {
          expect(findTimeInfo().text()).toContain(expectedStartDate);
        });
      },
    );
  });

  describe('date range selectors', () => {
    beforeEach(factory);

    it('shows a set of buttons to select the supported day ranges', () => {
      const supportedDayRanges = [30, 60, 90];

      expect(wrapper.find(ChartButtons).props('days')).toEqual(supportedDayRanges);
    });

    it('dispatches "setVulnerabilitiesHistoryDayRange" when a day range is selected', () => {
      const selectedDayRange = 30;
      wrapper.find(ChartButtons).vm.$emit('click', selectedDayRange);

      expect(actions.setVulnerabilitiesHistoryDayRange).toHaveBeenCalledTimes(1);
      expect(actions.setVulnerabilitiesHistoryDayRange.mock.calls[0][1]).toBe(selectedDayRange);
    });
  });

  describe('charts table', () => {
    describe.each(['Critical', 'Medium', 'High', 'Low'])(
      'for the given severity level "%s"',
      severityLevel => {
        beforeEach(() => {
          factory({ stubs: { GlTable: false } });
        });

        it('shows a severity badge', () => {
          expect(findSeverityBadgeForLevel(severityLevel).exists()).toBe(true);
        });

        it('shows a chart', () => {
          expect(findSparklineChartForLevel(severityLevel).exists()).toBe(true);
        });
      },
    );

    it.each`
      countPast | countCurrent | expectedOutput
      ${1}      | ${2}         | ${'+100%'}
      ${100}    | ${1}         | ${'-99%'}
      ${1}      | ${1}         | ${'+0%'}
      ${0}      | ${1}         | ${'-'}
    `(
      'shows "$expectedOutput" when the vulnerabilities changed from "$countPast" to "$countCurrent"',
      ({ countPast, countCurrent, expectedOutput }) => {
        factory({
          vulnerabilitiesCount: [countPast, countCurrent],
          stubs: {
            GlTable: false,
          },
        });

        expect(findChangeInPercent().text()).toBe(expectedOutput);
      },
    );

    it.each`
      vulnerabilitiesCount | expectedOutput
      ${[1, 2, 3]}         | ${'3'}
    `('shows the current vulnerabilities count', ({ vulnerabilitiesCount, expectedOutput }) => {
      factory({ vulnerabilitiesCount, stubs: { GlTable: false } });
      expect(findCurrentVulnerabilitiesCount().text()).toBe(expectedOutput);
    });
  });
});
