import { shallowMount } from '@vue/test-utils';
import { mockAssigneesList } from 'jest/boards/mock_data';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import IssueAssignees from '~/vue_shared/components/issue/issue_assignees.vue';

const TEST_CSS_CLASSES = 'test-classes';
const TEST_MAX_VISIBLE = 4;
const TEST_ICON_SIZE = 16;

describe('IssueAssigneesComponent', () => {
  let wrapper;
  let vm;

  const factory = props => {
    wrapper = shallowMount(IssueAssignees, {
      propsData: {
        assignees: mockAssigneesList,
        ...props,
      },
    });
    vm = wrapper.vm;
  };

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

  const findTooltipText = () => wrapper.find('.js-assignee-tooltip').text();
  const findAvatars = () => wrapper.findAll(UserAvatarLink);
  const findOverflowCounter = () => wrapper.find('.avatar-counter');

  it('returns default data props', () => {
    factory({ assignees: mockAssigneesList });
    expect(vm.iconSize).toBe(24);
    expect(vm.maxVisible).toBe(3);
    expect(vm.maxAssignees).toBe(99);
  });

  describe.each`
    numAssignees | maxVisible | expectedShown | expectedHidden
    ${0}         | ${3}       | ${0}          | ${''}
    ${1}         | ${3}       | ${1}          | ${''}
    ${2}         | ${3}       | ${2}          | ${''}
    ${3}         | ${3}       | ${3}          | ${''}
    ${4}         | ${3}       | ${2}          | ${'+2'}
    ${5}         | ${2}       | ${1}          | ${'+4'}
    ${1000}      | ${5}       | ${4}          | ${'99+'}
  `(
    'with assignees ($numAssignees) and maxVisible ($maxVisible)',
    ({ numAssignees, maxVisible, expectedShown, expectedHidden }) => {
      beforeEach(() => {
        factory({ assignees: Array(numAssignees).fill({}), maxVisible });
      });

      if (expectedShown) {
        it('shows assignee avatars', () => {
          expect(findAvatars().length).toEqual(expectedShown);
        });
      } else {
        it('does not show assignee avatars', () => {
          expect(findAvatars().length).toEqual(0);
        });
      }

      if (expectedHidden) {
        it('shows overflow counter', () => {
          const hiddenCount = numAssignees - expectedShown;

          expect(findOverflowCounter().exists()).toBe(true);
          expect(findOverflowCounter().text()).toEqual(expectedHidden.toString());
          expect(findOverflowCounter().attributes('title')).toEqual(
            `${hiddenCount} more assignees`,
          );
        });
      } else {
        it('does not show overflow counter', () => {
          expect(findOverflowCounter().exists()).toBe(false);
        });
      }
    },
  );

  describe('when mounted', () => {
    beforeEach(() => {
      factory({
        imgCssClasses: TEST_CSS_CLASSES,
        maxVisible: TEST_MAX_VISIBLE,
        iconSize: TEST_ICON_SIZE,
      });
    });

    it('computes alt text for assignee avatar', () => {
      expect(vm.avatarUrlTitle(mockAssigneesList[0])).toBe('Avatar for Terrell Graham');
    });

    it('renders component root element with class `issue-assignees`', () => {
      expect(wrapper.element.classList.contains('issue-assignees')).toBe(true);
    });

    it('renders assignee', () => {
      const data = findAvatars().wrappers.map(x => ({
        ...x.props(),
      }));

      const expected = mockAssigneesList.slice(0, TEST_MAX_VISIBLE - 1).map(x =>
        expect.objectContaining({
          linkHref: x.web_url,
          imgAlt: `Avatar for ${x.name}`,
          imgCssClasses: TEST_CSS_CLASSES,
          imgSrc: x.avatar_url,
          imgSize: TEST_ICON_SIZE,
        }),
      );

      expect(data).toEqual(expected);
    });

    describe('assignee tooltips', () => {
      it('renders "Assignee" header', () => {
        expect(findTooltipText()).toContain('Assignee');
      });

      it('renders assignee name', () => {
        expect(findTooltipText()).toContain('Terrell Graham');
      });

      it('renders assignee @username', () => {
        expect(findTooltipText()).toContain('@monserrate.gleichner');
      });

      it('does not render `@` when username not available', () => {
        const userName = 'User without username';
        factory({
          assignees: [
            {
              name: userName,
            },
          ],
        });

        const tooltipText = findTooltipText();

        expect(tooltipText).toContain(userName);
        expect(tooltipText).not.toContain('@');
      });
    });
  });
});
