import {
  DashboardsContext, ServiceContainer, ServiceState,
} from '@bthlabs/homehub-core';
import {mount} from 'enzyme';
import React from 'react';

import {Dashboard, DashboardItem, DummyWidget} from 'src/main/components';
import * as DashboardContainer from 'src/main/containers/DashboardContainer';

import {DashboardsContextFactory} from 'tests/__fixtures__/dashboardsContext';
import {FakeWidget} from 'tests/__fixtures__/services';
import {SettingsFactory} from 'tests/__fixtures__/settings';

describe('src/main/containers/DashboardContainer', () => {
  describe('ControlledDashboardContainer', () => {
    let fakeDashboardsContext = null;
    let fakeSettings = null;

    beforeEach(() => {
      fakeDashboardsContext = DashboardsContextFactory();
      fakeSettings = SettingsFactory();
    });

    it('handles grid layout change', () => {
      // Given
      const component = mount(
        <DashboardsContext.Provider value={fakeDashboardsContext}>
          <DashboardContainer.ControlledDashboardContainer
            settings={fakeSettings}
          />
        </DashboardsContext.Provider>
      );

      // When
      const dashboard = component.find(Dashboard).at(0);
      dashboard.invoke('onGridLayoutChange')([
        {i: 'fake_instance', x: 0, y: 0, w: 1, h: 1},
        {i: 'other_fake_instance', x: 1, y: 1, w: 1, h: 1},
      ]);

      // Then
      expect(fakeDashboardsContext.saveServiceLayout).toHaveBeenCalledWith(
        'fake_instance', {x: 0, y: 0, w: 1, h: 1}
      );
      expect(fakeDashboardsContext.saveServiceLayout).toHaveBeenCalledWith(
        'other_fake_instance', {x: 1, y: 1, w: 1, h: 1}
      );
    });

    it('configures and renders the dashboard', () => {
      // Given
      const component = mount(
        <DashboardsContext.Provider value={fakeDashboardsContext}>
          <DashboardContainer.ControlledDashboardContainer
            settings={fakeSettings}
          />
        </DashboardsContext.Provider>
      );

      const expectedLayout = [
        {i: 'fake_instance', x: 0, y: 0, w: 1, h: 1, minW: 1, minH: 1},
        {i: 'other_fake_instance', x: 0, y: 1, w: 1, h: 1},
      ];

      // When
      const dashboard = component.find(Dashboard).at(0);

      // Then
      expect(dashboard.exists()).toBe(true);
      expect(dashboard.prop('readOnly')).toBe(false);
      expect(dashboard.prop('layout')).toEqual(expectedLayout);
    });

    it('configures and renders the dashboard as read-only', () => {
      // Given
      fakeSettings.READ_ONLY = true;

      const component = mount(
        <DashboardsContext.Provider value={fakeDashboardsContext}>
          <DashboardContainer.ControlledDashboardContainer
            settings={fakeSettings}
          />
        </DashboardsContext.Provider>
      );

      // When
      const dashboard = component.find(Dashboard).at(0);

      // Then
      expect(dashboard.exists()).toBe(true);
      expect(dashboard.prop('readOnly')).toBe(true);
    });

    it('configures and renders a ServiceContainer for services', () => {
      // Given
      const component = mount(
        <DashboardsContext.Provider value={fakeDashboardsContext}>
          <DashboardContainer.ControlledDashboardContainer
            settings={fakeSettings}
          />
        </DashboardsContext.Provider>
      );

      // When
      const serviceContainers = component.find(ServiceContainer);

      // Then
      expect(serviceContainers.length).toEqual(2);

      const serviceContainer = serviceContainers.at(0);
      expect(serviceContainer.prop('instance')).toEqual(
        fakeDashboardsContext.dashboards[0].services[0].instance
      );
      expect(serviceContainer.prop('kind')).toEqual(
        fakeDashboardsContext.dashboards[0].services[0].kind
      );
      expect(serviceContainer.prop('readOnly')).toBe(false);
    });

    it('configures and renders ServiceContainers as read-oniy', () => {
      // Given
      fakeSettings.READ_ONLY = true;

      const component = mount(
        <DashboardsContext.Provider value={fakeDashboardsContext}>
          <DashboardContainer.ControlledDashboardContainer
            settings={fakeSettings}
          />
        </DashboardsContext.Provider>
      );

      // When
      const serviceContainers = component.find(ServiceContainer);
      const serviceContainer = serviceContainers.at(0);

      // Then
      expect(serviceContainer.prop('readOnly')).toBe(true);
    });

    it('configures and renders a DashboardItem for services', () => {
      // Given
      const component = mount(
        <DashboardsContext.Provider value={fakeDashboardsContext}>
          <DashboardContainer.ControlledDashboardContainer
            settings={fakeSettings}
          />
        </DashboardsContext.Provider>
      );

      // When
      const dashboardItems = component.find(DashboardItem);

      // Then
      expect(dashboardItems.length).toEqual(2);

      const dashboardItem = dashboardItems.at(0);
      expect(dashboardItem.prop('settingsView')).toEqual(
        FakeWidget.settingsView
      );
      expect(dashboardItem.prop('settingsViewProps').settings).toEqual(
        fakeSettings
      );

      expect(dashboardItems.at(1).prop('settingsView')).not.toBeDefined();
    });

    it('configures and renders a widget for services', () => {
      // Given
      const component = mount(
        <DashboardsContext.Provider value={fakeDashboardsContext}>
          <DashboardContainer.ControlledDashboardContainer
            settings={fakeSettings}
          />
        </DashboardsContext.Provider>
      );

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

      // Then
      expect(widget.exists()).toBe(true);
      expect(widget.prop('appearance')).toEqual(
        fakeDashboardsContext.dashboards[0].services[0].characteristics.appearance
      );
      expect(widget.prop('service')).toEqual(
        fakeDashboardsContext.dashboards[0].services[0]
      );
      expect(widget.prop('serviceState')).toBeInstanceOf(ServiceState);
      expect(widget.prop('setServiceState')).toBeDefined();
    });

    it('renders a DummyWidget for service with unknown widget', () => {
      // Given
      const component = mount(
        <DashboardsContext.Provider value={fakeDashboardsContext}>
          <DashboardContainer.ControlledDashboardContainer
            settings={fakeSettings}
          />
        </DashboardsContext.Provider>
      );

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

      // Then
      expect(widget.exists()).toBe(true);
      expect(widget.prop('service')).toEqual(
        fakeDashboardsContext.dashboards[0].services[1]
      );
    });
  });
});
