import Vue from 'vue';
import Assignee from '~/sidebar/components/assignees/assignees.vue';
import UsersMock from './mock_data';
import UsersMockHelper from '../helpers/user_mock_data_helper';

describe('Assignee component', () => {
  let component;
  let AssigneeComponent;

  beforeEach(() => {
    AssigneeComponent = Vue.extend(Assignee);
  });

  describe('No assignees/users', () => {
    it('displays no assignee icon when collapsed', () => {
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000',
          users: [],
          editable: false,
        },
      }).$mount();

      const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');

      expect(collapsed.childElementCount).toEqual(1);
      expect(collapsed.children[0].getAttribute('aria-label')).toEqual('None');
      expect(collapsed.children[0].classList.contains('fa')).toEqual(true);
      expect(collapsed.children[0].classList.contains('fa-user')).toEqual(true);
    });

    it('displays only "None" when no users are assigned and the issue is read-only', () => {
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000',
          users: [],
          editable: false,
        },
      }).$mount();
      const componentTextNoUsers = component.$el.querySelector('.assign-yourself').innerText.trim();

      expect(componentTextNoUsers).toBe('None');
      expect(componentTextNoUsers.indexOf('assign yourself')).toEqual(-1);
    });

    it('displays only "None" when no users are assigned and the issue can be edited', () => {
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000',
          users: [],
          editable: true,
        },
      }).$mount();
      const componentTextNoUsers = component.$el.querySelector('.assign-yourself').innerText.trim();

      expect(componentTextNoUsers.indexOf('None')).toEqual(0);
      expect(componentTextNoUsers.indexOf('assign yourself')).toBeGreaterThan(0);
    });

    it('emits the assign-self event when "assign yourself" is clicked', () => {
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000',
          users: [],
          editable: true,
        },
      }).$mount();

      spyOn(component, '$emit');
      component.$el.querySelector('.assign-yourself .btn-link').click();

      expect(component.$emit).toHaveBeenCalledWith('assign-self');
    });
  });

  describe('One assignee/user', () => {
    it('displays one assignee icon when collapsed', () => {
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000',
          users: [UsersMock.user],
          editable: false,
        },
      }).$mount();

      const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
      const assignee = collapsed.children[0];

      expect(collapsed.childElementCount).toEqual(1);
      expect(assignee.querySelector('.avatar').getAttribute('src')).toEqual(UsersMock.user.avatar);
      expect(assignee.querySelector('.avatar').getAttribute('alt')).toEqual(
        `${UsersMock.user.name}'s avatar`,
      );

      expect(assignee.querySelector('.author').innerText.trim()).toEqual(UsersMock.user.name);
    });

    it('Shows one user with avatar, username and author name', () => {
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000/',
          users: [UsersMock.user],
          editable: true,
        },
      }).$mount();

      expect(component.$el.querySelector('.author-link')).not.toBeNull();
      // The image
      expect(component.$el.querySelector('.author-link img').getAttribute('src')).toEqual(
        UsersMock.user.avatar,
      );
      // Author name
      expect(component.$el.querySelector('.author-link .author').innerText.trim()).toEqual(
        UsersMock.user.name,
      );
      // Username
      expect(component.$el.querySelector('.author-link .username').innerText.trim()).toEqual(
        `@${UsersMock.user.username}`,
      );
    });

    it('has the root url present in the assigneeUrl method', () => {
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000/',
          users: [UsersMock.user],
          editable: true,
        },
      }).$mount();

      expect(component.assigneeUrl(UsersMock.user).indexOf('http://localhost:3000/')).not.toEqual(
        -1,
      );
    });

    it('has correct "cannot merge" tooltip when user cannot merge', () => {
      const user = Object.assign({}, UsersMock.user, { can_merge: false });

      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000/',
          users: [user],
          editable: true,
          issuableType: 'merge_request',
        },
      }).$mount();

      expect(component.mergeNotAllowedTooltipMessage).toEqual('Cannot merge');
    });
  });

  describe('Two or more assignees/users', () => {
    it('has correct "cannot merge" tooltip when one user can merge', () => {
      const users = UsersMockHelper.createNumberRandomUsers(3);
      users[0].can_merge = true;
      users[1].can_merge = false;
      users[2].can_merge = false;

      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000/',
          users,
          editable: true,
          issuableType: 'merge_request',
        },
      }).$mount();

      expect(component.mergeNotAllowedTooltipMessage).toEqual('1/3 can merge');
    });

    it('has correct "cannot merge" tooltip when no user can merge', () => {
      const users = UsersMockHelper.createNumberRandomUsers(2);
      users[0].can_merge = false;
      users[1].can_merge = false;

      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000/',
          users,
          editable: true,
          issuableType: 'merge_request',
        },
      }).$mount();

      expect(component.mergeNotAllowedTooltipMessage).toEqual('No one can merge');
    });

    it('has correct "cannot merge" tooltip when more than one user can merge', () => {
      const users = UsersMockHelper.createNumberRandomUsers(3);
      users[0].can_merge = false;
      users[1].can_merge = true;
      users[2].can_merge = true;

      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000/',
          users,
          editable: true,
          issuableType: 'merge_request',
        },
      }).$mount();

      expect(component.mergeNotAllowedTooltipMessage).toEqual('2/3 can merge');
    });

    it('has no "cannot merge" tooltip when every user can merge', () => {
      const users = UsersMockHelper.createNumberRandomUsers(2);
      users[0].can_merge = true;
      users[1].can_merge = true;

      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000/',
          users,
          editable: true,
          issuableType: 'merge_request',
        },
      }).$mount();

      expect(component.mergeNotAllowedTooltipMessage).toEqual(null);
    });

    it('displays two assignee icons when collapsed', () => {
      const users = UsersMockHelper.createNumberRandomUsers(2);
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000',
          users,
          editable: false,
        },
      }).$mount();

      const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');

      expect(collapsed.childElementCount).toEqual(2);

      const first = collapsed.children[0];

      expect(first.querySelector('.avatar').getAttribute('src')).toEqual(users[0].avatar);
      expect(first.querySelector('.avatar').getAttribute('alt')).toEqual(
        `${users[0].name}'s avatar`,
      );

      expect(first.querySelector('.author').innerText.trim()).toEqual(users[0].name);

      const second = collapsed.children[1];

      expect(second.querySelector('.avatar').getAttribute('src')).toEqual(users[1].avatar);
      expect(second.querySelector('.avatar').getAttribute('alt')).toEqual(
        `${users[1].name}'s avatar`,
      );

      expect(second.querySelector('.author').innerText.trim()).toEqual(users[1].name);
    });

    it('displays one assignee icon and counter when collapsed', () => {
      const users = UsersMockHelper.createNumberRandomUsers(3);
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000',
          users,
          editable: false,
        },
      }).$mount();

      const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');

      expect(collapsed.childElementCount).toEqual(2);

      const first = collapsed.children[0];

      expect(first.querySelector('.avatar').getAttribute('src')).toEqual(users[0].avatar);
      expect(first.querySelector('.avatar').getAttribute('alt')).toEqual(
        `${users[0].name}'s avatar`,
      );

      expect(first.querySelector('.author').innerText.trim()).toEqual(users[0].name);

      const second = collapsed.children[1];

      expect(second.querySelector('.avatar-counter').innerText.trim()).toEqual('+2');
    });

    it('Shows two assignees', () => {
      const users = UsersMockHelper.createNumberRandomUsers(2);
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000',
          users,
          editable: true,
        },
      }).$mount();

      expect(component.$el.querySelectorAll('.user-item').length).toEqual(users.length);
      expect(component.$el.querySelector('.user-list-more')).toBe(null);
    });

    it('sets tooltip container to body', () => {
      const users = UsersMockHelper.createNumberRandomUsers(2);
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000',
          users,
          editable: true,
        },
      }).$mount();

      expect(component.$el.querySelector('.user-link').getAttribute('data-container')).toBe('body');
    });

    it('Shows the "show-less" assignees label', done => {
      const users = UsersMockHelper.createNumberRandomUsers(6);
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000',
          users,
          editable: true,
        },
      }).$mount();

      expect(component.$el.querySelectorAll('.user-item').length).toEqual(
        component.defaultRenderCount,
      );

      expect(component.$el.querySelector('.user-list-more')).not.toBe(null);
      const usersLabelExpectation = users.length - component.defaultRenderCount;

      expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim()).not.toBe(
        `+${usersLabelExpectation} more`,
      );
      component.toggleShowLess();
      Vue.nextTick(() => {
        expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim()).toBe(
          '- show less',
        );
        done();
      });
    });

    it('Shows the "show-less" when "n+ more " label is clicked', done => {
      const users = UsersMockHelper.createNumberRandomUsers(6);
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000',
          users,
          editable: true,
        },
      }).$mount();

      component.$el.querySelector('.user-list-more .btn-link').click();
      Vue.nextTick(() => {
        expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim()).toBe(
          '- show less',
        );
        done();
      });
    });

    it('gets the count of avatar via a computed property ', () => {
      const users = UsersMockHelper.createNumberRandomUsers(6);
      component = new AssigneeComponent({
        propsData: {
          rootPath: 'http://localhost:3000',
          users,
          editable: true,
        },
      }).$mount();

      expect(component.sidebarAvatarCounter).toEqual(`+${users.length - 1}`);
    });

    describe('n+ more label', () => {
      beforeEach(() => {
        const users = UsersMockHelper.createNumberRandomUsers(6);
        component = new AssigneeComponent({
          propsData: {
            rootPath: 'http://localhost:3000',
            users,
            editable: true,
          },
        }).$mount();
      });

      it('shows "+1 more" label', () => {
        expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim()).toBe(
          '+ 1 more',
        );
      });

      it('shows "show less" label', done => {
        component.toggleShowLess();

        Vue.nextTick(() => {
          expect(component.$el.querySelector('.user-list-more .btn-link').innerText.trim()).toBe(
            '- show less',
          );
          done();
        });
      });
    });
  });
});
