import Popup from '@bthlabs/react-custom-popup';
import {shallow} from 'enzyme';
import React from 'react';

import {AppearancePopup, WidgetSettingsModal} from 'src/main/components';
import * as DashboardItem from 'src/main/components/DashboardItem';

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

describe('src/main/components/ControlledDashboardItem', () => {
  describe('ControlledDashboardItem', () => {
    let fakeServiceState = null;
    let fakeSettings = null;
    let mockOnAppearancePopupColorChange = null;
    let mockOnServiceRestartButtonClick = null;
    let mockOnSettingsButtonClick = null;
    let mockOnSettingsModalClose = null;
    let mockOnSettingsModalNukeButtonClick = null;
    let mockOnSettingsModalSaveButtonClick = null;

    beforeEach(() => {
      fakeServiceState = jasmine.createSpyObj('ServiceState', ['isLoading']);
      fakeServiceState.isLoading.and.returnValue(false);
      fakeSettings = SettingsFactory();
      mockOnAppearancePopupColorChange = jasmine.createSpy();
      mockOnServiceRestartButtonClick = jasmine.createSpy();
      mockOnSettingsButtonClick = jasmine.createSpy();
      mockOnSettingsModalClose = jasmine.createSpy();
      mockOnSettingsModalNukeButtonClick = jasmine.createSpy();
      mockOnSettingsModalSaveButtonClick = jasmine.createSpy();
    });

    it('renders the children', () => {
      // Given
      const children = <span>It works!</span>;
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={false}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={null}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          {children}
        </DashboardItem.ControlledDashboardItem>
      );

      // Then
      expect(component.contains(children)).toBe(true);
    });

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

      const children = <span>It works!</span>;

      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={false}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={null}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          {children}
        </DashboardItem.ControlledDashboardItem>
      );

      // Then
      expect(component.contains(children)).toBe(true);
      expect(component.find('.draggable-handle').exists()).toBe(false);
      expect(component.find('WidgetToolbarItem[_hint="Restart"]').exists()).toBe(
        false
      );
      expect(component.find('WidgetToolbarItem[_hint="Appearance"]').exists()).toBe(
        false
      );
      expect(component.find('WidgetToolbarItem[_hint="Settings"]').exists()).toBe(
        false
      );
      expect(component.find('WidgetToolbarItem[_hint="Delete"]').exists()).toBe(
        false
      );
      expect(component.find(WidgetSettingsModal).exists()).toBe(false);
      expect(component.find(AppearancePopup).exists()).toBe(false);
    });

    it('renders as read-only if hasSettingsView is true', () => {
      // Given
      fakeSettings.READ_ONLY = true;

      const children = <span>It works!</span>;

      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={true}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={<span>Settings</span>}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          {children}
        </DashboardItem.ControlledDashboardItem>
      );

      // Then
      expect(component.contains(children)).toBe(true);
      expect(component.find('.draggable-handle').exists()).toBe(false);
      expect(component.find('WidgetToolbarItem[_hint="Restart"]').exists()).toBe(
        false
      );
      expect(component.find('WidgetToolbarItem[_hint="Appearance"]').exists()).toBe(
        false
      );
      expect(component.find('WidgetToolbarItem[_hint="Settings"]').exists()).toBe(
        false
      );
      expect(component.find('WidgetToolbarItem[_hint="Delete"]').exists()).toBe(
        false
      );
      expect(component.find(WidgetSettingsModal).exists()).toBe(false);
      expect(component.find(AppearancePopup).exists()).toBe(false);
    });

    it('renders the draggable handle', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={false}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={null}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // Then
      expect(component.find('.draggable-handle').exists()).toBe(true);
    });

    it('does not render the restart toolbar item if serviceState is null', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={false}
          serviceState={null}
          settings={fakeSettings}
          settingsView={null}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // Then
      expect(component.find('WidgetToolbarItem[_hint="Restart"]').exists()).toBe(
        false
      );
    });

    it('does not render the restart toolbar item if service state is loading', () => {
      // Given
      fakeServiceState.isLoading.and.returnValue(true);
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={false}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={null}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // Then
      expect(component.find('WidgetToolbarItem[_hint="Restart"]').exists()).toBe(
        false
      );
    });

    it('configures and renders the restart toolbar item', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={false}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={null}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // When
      const restartItem = component.find('WidgetToolbarItem[_hint="Restart"]');

      // Then
      expect(restartItem.exists()).toBe(true);
      expect(restartItem.prop('onClick')).toEqual(
        mockOnServiceRestartButtonClick
      );
    });

    it('configures and renders the appearance toolbar item', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={false}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={null}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // When
      const appearanceItem = component.find(
        'WidgetToolbarItem[_hint="Appearance"]'
      );

      // Then
      expect(appearanceItem.exists()).toBe(true);
    });

    it('displays the appearance popup when appearance toolbar item is clicked', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={false}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={null}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // When
      component.find('WidgetToolbarItem[_hint="Appearance"]').simulate(
        'click'
      );

      // Then
      const popup = component.find(Popup).at(0);
      expect(popup.prop('visible')).toBe(true);
    });

    it('does not render the settings toolbar item if hasSettingsView is false', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={false}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={null}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // Then
      expect(component.find('WidgetToolbarItem[_hint="Settings"]').exists()).toBe(
        false
      );
    });

    it('configures and renders the settings toolbar item', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={true}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={<span>Settings</span>}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // When
      const settingsItem = component.find(
        'WidgetToolbarItem[_hint="Settings"]'
      );

      // Then
      expect(settingsItem.exists()).toBe(true);
      expect(settingsItem.prop('onClick')).toEqual(mockOnSettingsButtonClick);
    });

    it('does not render the delete toolbar item if hasSettingsView is true', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={true}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={<span>Settings</span>}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // Then
      expect(component.find('WidgetToolbarItem[_hint="Delete"]').exists()).toBe(
        false
      );
    });

    it('configures and renders the delete toolbar item', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={false}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={null}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // When
      const deleteItem = component.find(
        'WidgetToolbarItem[_hint="Delete"]'
      );

      // Then
      expect(deleteItem.exists()).toBe(true);
      expect(deleteItem.prop('onClick')).toEqual(
        mockOnSettingsModalNukeButtonClick
      );
    });

    it('does not render the WidgetSettingsModal if hasSettingsView is false', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={false}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={null}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // When
      const widgetSettingsModal = component.find(WidgetSettingsModal).at(0);

      // Then
      expect(widgetSettingsModal.exists()).toBe(false);
    });

    it('configures and renders the WidgetSettingsModal', () => {
      // Given
      const settingsView = <span>Settings</span>;
      const settingsViewProps = {spam: true};
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={true}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={settingsView}
          settingsViewProps={settingsViewProps}
          showSettingsModal={true}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // When
      const widgetSettingsModal = component.find(WidgetSettingsModal).at(0);

      // Then
      expect(widgetSettingsModal.exists()).toBe(true);
      expect(widgetSettingsModal.prop('buttons').length).toEqual(1);
      expect(widgetSettingsModal.prop('settingsView')).toEqual(settingsView);
      expect(widgetSettingsModal.prop('settingsViewProps')).toEqual(
        settingsViewProps
      );
      expect(widgetSettingsModal.prop('show')).toBe(true);
      expect(widgetSettingsModal.prop('onClose')).toEqual(
        mockOnSettingsModalClose
      );
      expect(widgetSettingsModal.prop('onCancelButtonClick')).toEqual(
        mockOnSettingsModalClose
      );
      expect(widgetSettingsModal.prop('onSaveButtonClick')).toEqual(
        mockOnSettingsModalSaveButtonClick
      );

      const nukeButtonComponent = shallow(
        widgetSettingsModal.prop('buttons')[0]
      );

      expect(nukeButtonComponent.isEmptyRender()).toBe(false);
      expect(nukeButtonComponent.prop('onClick')).toEqual(
        mockOnSettingsModalNukeButtonClick
      );
    });

    it('configures and renders the appearance popup wrapper', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={true}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={<span>Settings</span>}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // When
      const popup = component.find(Popup).at(0);

      // Then
      expect(popup.exists()).toBe(true);
      expect(popup.prop('visible')).toBe(false);
    });

    it('hides the appearance popup wrapper when the overlay is clicked', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={true}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={<span>Settings</span>}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // When
      component.find('WidgetToolbarItem[_hint="Appearance"]').simulate(
        'click'
      );
      component.find(Popup).at(0).invoke('onOverlayClick')();

      // Then
      const popup = component.find(Popup).at(0);
      expect(popup.prop('visible')).toBe(false);
    });

    it('configures and renders the appearance popup view', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={true}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={<span>Settings</span>}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // When
      const popupView = component.find(AppearancePopup).at(0);

      // Then
      expect(popupView.exists()).toBe(true);
    });

    it('handles the AppearancePopup color change', () => {
      // Given
      const component = shallow(
        <DashboardItem.ControlledDashboardItem
          hasSettingsView={true}
          serviceState={fakeServiceState}
          settings={fakeSettings}
          settingsView={<span>Settings</span>}
          settingsViewProps={{}}
          showSettingsModal={false}
          onAppearancePopupColorChange={mockOnAppearancePopupColorChange}
          onServiceRestartButtonClick={mockOnServiceRestartButtonClick}
          onSettingsButtonClick={mockOnSettingsButtonClick}
          onSettingsModalClose={mockOnSettingsModalClose}
          onSettingsModalNukeButtonClick={mockOnSettingsModalNukeButtonClick}
          onSettingsModalSaveButtonClick={mockOnSettingsModalSaveButtonClick}
        >
          <span>It works!</span>
        </DashboardItem.ControlledDashboardItem>
      );

      // When
      component.find('WidgetToolbarItem[_hint="Appearance"]').simulate(
        'click'
      );
      component.find(AppearancePopup).at(0).invoke('onColorChange')('red');

      // Then
      expect(component.find(Popup).at(0).prop('visible')).toBe(false);
      expect(mockOnAppearancePopupColorChange).toHaveBeenCalledWith('red');
    });
  });
});
