import { shallow } from 'enzyme';
import React from 'react';
import { Label } from 'semantic-ui-react';

import {
  SiteVersion,
  mapStateToProps,
} from './SiteVersion';

const createSite = () => {
  const site = {
    autoupdate: jest.fn().mockReturnValue(undefined),
    AUTOUPDATE_STATUS_IDLE: 'idle',
    AUTOUPDATE_STATUS_UPDATING: 'updating',
    AUTOUPDATE_STATUS_PENDING_RESTART: 'pending',
    AUTOUPDATE_STATUS_ERROR: 'error',
    getUpdateProgress: jest.fn().mockReturnValue(42),
    getUpdateStatus: jest.fn().mockReturnValue('idle'),
    getVersion: jest.fn().mockReturnValue('1.2.3'),
  };

  return site;
};

describe('mapStateToProps', () => {
  let site;

  beforeEach(() => {
    site = createSite();
  });

  it('retrieves update progress from the site', () => {
    mapStateToProps(null, { site });
    expect(site.getUpdateProgress).toHaveBeenCalled();
  });

  it('passes update progress to the component', () => {
    const props = mapStateToProps(null, { site });
    expect(props.updateProgress).toBe(42);
  });

  it('retrieves update status from the site', () => {
    mapStateToProps(null, { site });
    expect(site.getUpdateStatus).toHaveBeenCalled();
  });

  it('passes update status to the component', () => {
    const props = mapStateToProps(null, { site });
    expect(props.updateStatus).toBe(site.AUTOUPDATE_STATUS_IDLE);
  });

  it('retrieves the version from the site', () => {
    mapStateToProps(null, { site });
    expect(site.getVersion).toHaveBeenCalled();
  });

  it('passes the version to the component', () => {
    const props = mapStateToProps(null, { site });
    expect(props.version).toBe('1.2.3');
  });
});

describe('SiteVersion component', () => {
  let site;

  let wrapper;

  beforeEach(() => {
    site = createSite();
    wrapper = shallow(
      <SiteVersion
        site={ site }
        updateStatus={ site.AUTOUPDATE_STATUS_IDLE }
        version="1.2.3"
      />
    );
  });

  it('renders', () => {
    expect(wrapper).toExist();
  });

  it('renders a div with the version', () => {
    expect(wrapper.find('div')).toExist();
    expect(wrapper.find('div').children()).toHaveText('Version 1.2.3');
  });

  it('suppresses output if the version is unavailable', () => {
    wrapper.setProps({ version: undefined });
    expect(wrapper).toBeEmptyRender();
  });

  it('displays when an update is ready', () => {
    wrapper.setProps({ updateStatus: site.AUTOUPDATE_STATUS_PENDING_RESTART });
    expect(wrapper.find('div').children()).toHaveText('Update ready');
  });

  it('displays when an update is in progress', () => {
    wrapper.setProps({
      updateProgress: 32.21,
      updateStatus: site.AUTOUPDATE_STATUS_UPDATING,
    });
    expect(wrapper.find('div').children()).toHaveText('Updating: 32%');
  });

  it('displays when an update failed', () => {
    wrapper.setProps({ updateStatus: site.AUTOUPDATE_STATUS_ERROR });
    expect(wrapper.find('div').children()).toHaveText('Update failed');
  });

  it('can allow updates to be triggered', () => {
    wrapper.setProps({ clickable: true });
    expect(site.autoupdate).not.toHaveBeenCalled();
    wrapper.find('div').simulate('click');
    expect(site.autoupdate).toHaveBeenCalled();
  });

  it('ignores clicks when the trigger is disabled', () => {
    expect(site.autoupdate).not.toHaveBeenCalled();
    wrapper.find('div').simulate('click');
    expect(site.autoupdate).not.toHaveBeenCalled();
  });

  it('passes unknown props through to the div', () => {
    wrapper.setProps({ unknown: 'value' });
    expect(wrapper.find('div')).toHaveProp('unknown', 'value');
  });

  it('avoids passing internal props through to the div', () => {
    const div = wrapper.find('div');
    expect(div).not.toHaveProp('clickable');
    expect(div).not.toHaveProp('site');
    expect(div).not.toHaveProp('updateProgress');
    expect(div).not.toHaveProp('updateStatus');
    expect(div).not.toHaveProp('version');
  });

  it('can render as a string component', () => {
    wrapper.setProps({ as: 'a' });
    expect(wrapper.find('div')).not.toExist();
    expect(wrapper.find('a')).toExist();
  });

  it('can render as a functional component', () => {
    wrapper.setProps({ as: Label });
    expect(wrapper.find('div')).not.toExist();
    expect(wrapper.find('Label')).toExist();
  });
});
