import { shallowMount } from '@vue/test-utils';
import { TEST_HOST } from 'helpers/test_constants';
import { GlLoadingIcon } from '@gitlab/ui';
import { listen } from 'codesandbox-api';
import ClientsideNavigator from '~/ide/components/preview/navigator.vue';

jest.mock('codesandbox-api', () => ({
  listen: jest.fn().mockReturnValue(jest.fn()),
}));

describe('IDE clientside preview navigator', () => {
  let wrapper;
  let manager;
  let listenHandler;

  const findBackButton = () => wrapper.findAll('button').at(0);
  const findForwardButton = () => wrapper.findAll('button').at(1);
  const findRefreshButton = () => wrapper.findAll('button').at(2);

  beforeEach(() => {
    listen.mockClear();
    manager = { bundlerURL: TEST_HOST, iframe: { src: '' } };

    wrapper = shallowMount(ClientsideNavigator, { propsData: { manager } });
    [[listenHandler]] = listen.mock.calls;
  });

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

  it('renders readonly URL bar', () => {
    listenHandler({ type: 'urlchange', url: manager.bundlerURL });
    return wrapper.vm.$nextTick(() => {
      expect(wrapper.find('input[readonly]').element.value).toBe('/');
    });
  });

  it('renders loading icon by default', () => {
    expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
  });

  it('removes loading icon when done event is fired', () => {
    listenHandler({ type: 'done' });
    return wrapper.vm.$nextTick(() => {
      expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
    });
  });

  it('does not count visiting same url multiple times', () => {
    listenHandler({ type: 'done' });
    listenHandler({ type: 'done', url: `${TEST_HOST}/url1` });
    listenHandler({ type: 'done', url: `${TEST_HOST}/url1` });
    return wrapper.vm.$nextTick().then(() => {
      expect(findBackButton().attributes('disabled')).toBe('disabled');
    });
  });

  it('unsubscribes from listen on destroy', () => {
    const unsubscribeFn = listen();

    wrapper.destroy();
    expect(unsubscribeFn).toHaveBeenCalled();
  });

  describe('back button', () => {
    beforeEach(() => {
      listenHandler({ type: 'done' });
      listenHandler({ type: 'urlchange', url: TEST_HOST });
      return wrapper.vm.$nextTick();
    });

    it('is disabled by default', () => {
      expect(findBackButton().attributes('disabled')).toBe('disabled');
    });

    it('is enabled when there is previous entry', () => {
      listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
      return wrapper.vm.$nextTick().then(() => {
        findBackButton().trigger('click');
        expect(findBackButton().attributes('disabled')).toBeFalsy();
      });
    });

    it('is disabled when there is no previous entry', () => {
      listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
      return wrapper.vm
        .$nextTick()
        .then(() => {
          findBackButton().trigger('click');

          return wrapper.vm.$nextTick();
        })
        .then(() => {
          expect(findBackButton().attributes('disabled')).toBe('disabled');
        });
    });

    it('updates manager iframe src', () => {
      listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
      listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url2` });
      return wrapper.vm.$nextTick().then(() => {
        findBackButton().trigger('click');

        expect(manager.iframe.src).toBe(`${TEST_HOST}/url1`);
      });
    });
  });

  describe('forward button', () => {
    beforeEach(() => {
      listenHandler({ type: 'done' });
      listenHandler({ type: 'urlchange', url: TEST_HOST });
      return wrapper.vm.$nextTick();
    });

    it('is disabled by default', () => {
      expect(findForwardButton().attributes('disabled')).toBe('disabled');
    });

    it('is enabled when there is next entry', () => {
      listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
      return wrapper.vm
        .$nextTick()
        .then(() => {
          findBackButton().trigger('click');
          return wrapper.vm.$nextTick();
        })
        .then(() => {
          expect(findForwardButton().attributes('disabled')).toBeFalsy();
        });
    });

    it('is disabled when there is no next entry', () => {
      listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
      return wrapper.vm
        .$nextTick()
        .then(() => {
          findBackButton().trigger('click');
          return wrapper.vm.$nextTick();
        })
        .then(() => {
          findForwardButton().trigger('click');
          return wrapper.vm.$nextTick();
        })
        .then(() => {
          expect(findForwardButton().attributes('disabled')).toBe('disabled');
        });
    });

    it('updates manager iframe src', () => {
      listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url1` });
      listenHandler({ type: 'urlchange', url: `${TEST_HOST}/url2` });
      return wrapper.vm.$nextTick().then(() => {
        findBackButton().trigger('click');

        expect(manager.iframe.src).toBe(`${TEST_HOST}/url1`);
      });
    });
  });

  describe('refresh button', () => {
    const url = `${TEST_HOST}/some_url`;
    beforeEach(() => {
      listenHandler({ type: 'done' });
      listenHandler({ type: 'urlchange', url });
      return wrapper.vm.$nextTick();
    });

    it('calls refresh with current path', () => {
      manager.iframe.src = 'something-other';
      findRefreshButton().trigger('click');

      expect(manager.iframe.src).toBe(url);
    });
  });
});
