import * as HomeHubCore from '@bthlabs/homehub-core';

import * as StateDataSource from 'src/main/dataSources/StateDataSource';

describe('src/lib/main/dataSources/StateDataSource', () => {
  beforeEach(() => {
    spyOn(HomeHubCore.API.State, 'get');
    spyOn(HomeHubCore.API.State, 'save');
    spyOn(HomeHubCore.LocalStorage, 'getItem');
    spyOn(HomeHubCore.LocalStorage, 'setItem');
  });

  afterEach(() => {
    StateDataSource.setOfflineMode(false);
  });

  describe('loadState', () => {
    it('throws an error if API call in online mode returns an error', async () => {
      // Given
      StateDataSource.setOfflineMode(false);
      HomeHubCore.API.State.get.and.resolveTo({
        error: 'FIAL',
      });

      // When
      let result = null;
      try {
        await StateDataSource.loadState();
      } catch (error) {
        result = error;
      }

      // Then
      expect(result).toEqual('FIAL');
    });

    it('returns state loaded from the API in online mode', async () => {
      // Given
      StateDataSource.setOfflineMode(false);
      const data = {dashboards: []};
      HomeHubCore.API.State.get.and.resolveTo({
        data: data,
      });

      // When
      const result = await StateDataSource.loadState();

      // Then
      expect(result).toEqual(data);
      expect(HomeHubCore.API.State.get).toHaveBeenCalled();
      expect(HomeHubCore.LocalStorage.getItem).not.toHaveBeenCalled();
    });

    it('returns state loaded from local storage in offline mode', async () => {
      // Given
      StateDataSource.setOfflineMode(true);
      const data = {dashboards: []};
      HomeHubCore.LocalStorage.getItem.and.returnValue(JSON.stringify(data));

      // When
      const result = await StateDataSource.loadState();

      // Then
      expect(result).toEqual(data);
      expect(HomeHubCore.API.State.get).not.toHaveBeenCalled();
      expect(HomeHubCore.LocalStorage.getItem).toHaveBeenCalledWith('state');
    });

    it('returns initial state if it is missing in local storage in offline mode', async () => {
      // Given
      StateDataSource.setOfflineMode(true);
      HomeHubCore.LocalStorage.getItem.and.returnValue(null);

      // When
      const result = await StateDataSource.loadState();

      // Then
      expect(result.dashboards.length).toEqual(1);
    });
  });

  describe('doSaveState', () => {
    let fakeState = null;

    beforeEach(() => {
      fakeState = {
        dashboards: [
          {
            id: 'testing',
            name: 'Testing',
            services: [],
          },
        ],
      };
    });

    it('throws an error if API call in online mode returns an error', async () => {
      // Given
      StateDataSource.setOfflineMode(false);
      HomeHubCore.API.State.save.and.resolveTo({
        error: 'FIAL',
      });

      // When
      let result = null;
      try {
        result = await StateDataSource.doSaveState(fakeState);
      } catch (error) {
        result = error;
      }

      // Then
      expect(result).toEqual('FIAL');
    });

    it('returns the result of the API call in online mode', async () => {
      // Given
      StateDataSource.setOfflineMode(false);
      HomeHubCore.API.State.save.and.resolveTo({
        data: true,
      });

      // When
      const result = await StateDataSource.doSaveState(fakeState);

      // Then
      expect(result).toBe(true);
      expect(HomeHubCore.API.State.save).toHaveBeenCalledWith(fakeState);
      expect(HomeHubCore.LocalStorage.setItem).not.toHaveBeenCalled();
    });

    it('returns the result of local storage save operation in offline mode', async () => {
      // Given
      StateDataSource.setOfflineMode(true);

      // When
      const result = await StateDataSource.doSaveState(fakeState);

      // Then
      expect(result).toBe(true);
      expect(HomeHubCore.API.State.save).not.toHaveBeenCalled();
      expect(HomeHubCore.LocalStorage.setItem).toHaveBeenCalledWith(
        'state', JSON.stringify(fakeState)
      );
    });
  });
});
