import {Widget} from '@bthlabs/homehub-components';
import {ServiceState} from '@bthlabs/homehub-core';
import {shallow} from 'enzyme';
import React from 'react';

import {Form} from 'src/components';
import * as TimeWidgetView from 'src/widgets/TimeWidgetView';

import {FakeService} from 'tests/__fixtures__/services';
import {SettingsFactory} from 'tests/__fixtures__/settings';

describe('src/widgets/TimeWidgetView', () => {
  describe('TimeWidgetSettingsView', () => {
    let fakeNextCharacteristics = null;
    let fakeSettings = null;
    let mockSetNextCharacteristics = null;

    beforeEach(() => {
      fakeNextCharacteristics = {
        locale: '',
        timeFormat: '',
        dateFormat: 'DATE_HUGE',
      };
      fakeSettings = SettingsFactory();
      mockSetNextCharacteristics = jasmine.createSpy();
    });

    it('calls the setNextCharacteristics callback when locale input changes', () => {
      // Given
      const component = shallow(
        <TimeWidgetView.TimeWidgetSettingsView
          nextCharacteristics={fakeNextCharacteristics}
          settings={fakeSettings}
          setNextCharacteristics={mockSetNextCharacteristics}
        />
      );

      // When
      component.find(Form.Control).at(0).simulate('change', {
        target: {value: 'en-gb'},
      });

      // Then
      expect(mockSetNextCharacteristics).toHaveBeenCalledWith({
        ...fakeNextCharacteristics,
        locale: 'en-gb',
      });
    });

    it('calls the setNextCharacteristics callback when time format input changes', () => {
      // Given
      const component = shallow(
        <TimeWidgetView.TimeWidgetSettingsView
          nextCharacteristics={fakeNextCharacteristics}
          settings={fakeSettings}
          setNextCharacteristics={mockSetNextCharacteristics}
        />
      );

      // When
      component.find(Form.Control).at(1).simulate('change', {
        target: {value: 'hh:mm a'},
      });

      // Then
      expect(mockSetNextCharacteristics).toHaveBeenCalledWith({
        ...fakeNextCharacteristics,
        timeFormat: 'hh:mm a',
      });
    });

    it('calls the setNextCharacteristics callback when date format input changes', () => {
      // Given
      const component = shallow(
        <TimeWidgetView.TimeWidgetSettingsView
          nextCharacteristics={fakeNextCharacteristics}
          settings={fakeSettings}
          setNextCharacteristics={mockSetNextCharacteristics}
        />
      );

      // When
      component.find(Form.Control).at(2).simulate('change', {
        target: {value: 'DATE_FULL'},
      });

      // Then
      expect(mockSetNextCharacteristics).toHaveBeenCalledWith({
        ...fakeNextCharacteristics,
        dateFormat: 'DATE_FULL',
      });
    });

    it('configures and renders the locale input', () => {
      // Given
      fakeNextCharacteristics = {
        ...fakeNextCharacteristics,
        locale: 'en-gb',
        timeFormat: 'hh:mm a',
        dateFormat: 'DATE_FULL',
      };
      const component = shallow(
        <TimeWidgetView.TimeWidgetSettingsView
          nextCharacteristics={fakeNextCharacteristics}
          settings={fakeSettings}
          setNextCharacteristics={mockSetNextCharacteristics}
        />
      );

      // When
      const input = component.find(Form.Control).at(0);

      // Then
      expect(input.exists()).toBe(true);
      expect(input.prop('value')).toEqual(fakeNextCharacteristics.locale);

      const options = input.find('option');
      expect(options.length).toEqual(3);
      expect(options.at(1).prop('value')).toEqual('en-us');
    });

    it('configures and renders the time format input', () => {
      // Given
      fakeNextCharacteristics = {
        ...fakeNextCharacteristics,
        locale: 'en-gb',
        timeFormat: 'hh:mm a',
        dateFormat: 'DATE_FULL',
      };
      const component = shallow(
        <TimeWidgetView.TimeWidgetSettingsView
          nextCharacteristics={fakeNextCharacteristics}
          settings={fakeSettings}
          setNextCharacteristics={mockSetNextCharacteristics}
        />
      );

      // When
      const input = component.find(Form.Control).at(1);

      // Then
      expect(input.exists()).toBe(true);
      expect(input.prop('value')).toEqual(fakeNextCharacteristics.timeFormat);

      const options = input.find('option');
      expect(options.length).toEqual(3);
      expect(options.at(1).prop('value')).toEqual('hh:mm a');
    });

    it('configures and renders the date format input', () => {
      // Given
      fakeNextCharacteristics = {
        ...fakeNextCharacteristics,
        locale: 'en-gb',
        timeFormat: 'hh:mm a',
        dateFormat: 'DATE_FULL',
      };
      const component = shallow(
        <TimeWidgetView.TimeWidgetSettingsView
          nextCharacteristics={fakeNextCharacteristics}
          settings={fakeSettings}
          setNextCharacteristics={mockSetNextCharacteristics}
        />
      );

      // When
      const input = component.find(Form.Control).at(2);

      // Then
      expect(input.exists()).toBe(true);
      expect(input.prop('value')).toEqual(fakeNextCharacteristics.dateFormat);

      const options = input.find('option');
      expect(options.length).toEqual(3);
      expect(options.at(0).prop('value')).toEqual('DATE_HUGE');
    });
  });

  describe('TimeWidgetView', () => {
    let fakeAppearance = null;
    let fakeService = null;
    let fakeServiceState = null;

    beforeEach(() => {
      fakeAppearance = {color: 'red'};
      fakeService = new FakeService({
        instance: 'testing',
        layout: {x: 0, y: 0, h: 1, w: 1},
      });
      fakeServiceState = new ServiceState({
        data: {
          time: '08:00 AM',
          date: '3 October 1987',
        },
      });
    });

    it('defines the widget attributes', () => {
      // Then
      expect(TimeWidgetView.TimeWidgetView.defaultLayout).toEqual({
        h: jasmine.any(Number),
        w: jasmine.any(Number),
      });
      expect(TimeWidgetView.TimeWidgetView.icon).toBeDefined();
      expect(TimeWidgetView.TimeWidgetView.layoutConstraints).toEqual({
        minH: jasmine.any(Number),
        minW: jasmine.any(Number),
      });
      expect(TimeWidgetView.TimeWidgetView.settingsView).toEqual(
        TimeWidgetView.TimeWidgetSettingsView
      );
      expect(TimeWidgetView.TimeWidgetView.title).toEqual('Time');
    });

    it('renders empty when service state is null', () => {
      // Given
      fakeServiceState = null;
      const component = shallow(
        <TimeWidgetView.TimeWidgetView
          appearance={fakeAppearance}
          service={fakeService}
          serviceState={fakeServiceState}
        />
      );

      // Then
      expect(component.isEmptyRender()).toBe(true);
    });

    it('configures and renders the Widget', () => {
      // Given
      const component = shallow(
        <TimeWidgetView.TimeWidgetView
          appearance={fakeAppearance}
          service={fakeService}
          serviceState={fakeServiceState}
        />
      );

      // When
      const widget = component.find(Widget).at(0);

      // Then
      expect(widget.exists()).toBe(true);
      expect(widget.prop('appearance')).toEqual(fakeAppearance);
      expect(widget.prop('instance')).toEqual(fakeService.instance);
      expect(widget.prop('kind')).toEqual(fakeService.kind);
      expect(widget.prop('layout')).toEqual(fakeService.layout);
    });

    it('renders the time string', () => {
      // Given
      const component = shallow(
        <TimeWidgetView.TimeWidgetView
          appearance={fakeAppearance}
          service={fakeService}
          serviceState={fakeServiceState}
        />
      );

      // When
      const h4 = component.find('h4').at(0);

      // Then
      expect(h4.text()).toEqual(fakeServiceState.data().time);
    });

    it('renders the date string', () => {
      // Given
      const component = shallow(
        <TimeWidgetView.TimeWidgetView
          appearance={fakeAppearance}
          service={fakeService}
          serviceState={fakeServiceState}
        />
      );

      // When
      const h6 = component.find('h6').at(0);

      // Then
      expect(h6.text()).toEqual(fakeServiceState.data().date);
    });
  });
});
