import { HttpHeaders } from '@angular/common/http';
import {
  fakeAsync,
  flush,
  TestBed,
  tick,
  waitForAsync,
} from '@angular/core/testing';
import {
  ActivatedRoute,
  Router,
} from '@angular/router';
import { StoreModule } from '@ngrx/store';
import {
  TranslateLoader,
  TranslateModule,
  TranslateService,
} from '@ngx-translate/core';
import {
  cold,
  getTestScheduler,
  hot,
} from 'jasmine-marbles';
import {
  of as observableOf,
  throwError as observableThrowError,
} from 'rxjs';
import { TestScheduler } from 'rxjs/testing';

import { environment } from '../../environments/environment';
import { storeModuleConfig } from '../app.reducer';
import { ErrorResponse } from '../core/cache/response.models';
import { RequestService } from '../core/data/request.service';
import { RequestError } from '../core/data/request-error.model';
import { HttpOptions } from '../core/dspace-rest/dspace-rest.service';
import { RouteService } from '../core/services/route.service';
import { Item } from '../core/shared/item.model';
import { SearchService } from '../core/shared/search/search.service';
import { SubmissionJsonPatchOperationsService } from '../core/submission/submission-json-patch-operations.service';
import { SubmissionRestService } from '../core/submission/submission-rest.service';
import { SubmissionScopeType } from '../core/submission/submission-scope-type';
import { MockActivatedRoute } from '../shared/mocks/active-router.mock';
import { getMockRequestService } from '../shared/mocks/request.service.mock';
import { RouterMock } from '../shared/mocks/router.mock';
import { getMockSearchService } from '../shared/mocks/search-service.mock';
import {
  mockSubmissionDefinition,
  mockSubmissionRestResponse,
} from '../shared/mocks/submission.mock';
import { TranslateLoaderMock } from '../shared/mocks/translate-loader.mock';
import { NotificationsService } from '../shared/notifications/notifications.service';
import { createFailedRemoteDataObject } from '../shared/remote-data.utils';
import { SubmissionJsonPatchOperationsServiceStub } from '../shared/testing/submission-json-patch-operations-service.stub';
import { SubmissionRestServiceStub } from '../shared/testing/submission-rest-service.stub';
import { SectionScope } from './objects/section-visibility.model';
import {
  CancelSubmissionFormAction,
  ChangeSubmissionCollectionAction,
  DiscardSubmissionAction,
  InitSubmissionFormAction,
  ResetSubmissionFormAction,
  SaveAndDepositSubmissionAction,
  SaveForLaterSubmissionFormAction,
  SaveSubmissionFormAction,
  SaveSubmissionSectionFormAction,
  SetActiveSectionAction,
} from './objects/submission-objects.actions';
import { submissionReducers } from './submission.reducers';
import { SubmissionService } from './submission.service';

describe('SubmissionService test suite', () => {
  const collectionId = '43fe1f8c-09a6-4fcf-9c78-5d4fed8f2c8f';
  const submissionId = '826';
  const sectionId = 'test';
  const subState = {
    objects: {
      826: {
        collection: '43fe1f8c-09a6-4fcf-9c78-5d4fed8f2c8f',
        definition: 'traditional',
        selfUrl: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826',
        activeSection: 'keyinformation',
        sections: {
          extraction: {
            config: '',
            mandatory: true,
            scope: SectionScope.Submission,
            sectionType: 'utils',
            visibility: {
              main: 'HIDDEN',
              other: 'HIDDEN',
            },
            collapsed: false,
            enabled: true,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          collection: {
            config: '',
            mandatory: true,
            scope: SectionScope.Submission,
            sectionType: 'collection',
            visibility: {
              main: 'HIDDEN',
              other: 'HIDDEN',
            },
            collapsed: false,
            enabled: true,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          keyinformation: {
            header: 'submit.progressbar.describe.keyinformation',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/keyinformation',
            mandatory: true,
            sectionType: 'submission-form',
            collapsed: false,
            enabled: true,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          indexing: {
            header: 'submit.progressbar.describe.indexing',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/indexing',
            mandatory: false,
            sectionType: 'submission-form',
            collapsed: false,
            enabled: false,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          publicationchannel: {
            header: 'submit.progressbar.describe.publicationchannel',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/publicationchannel',
            mandatory: true,
            sectionType: 'submission-form',
            collapsed: false,
            enabled: true,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: true,
          },
          acknowledgement: {
            header: 'submit.progressbar.describe.acknowledgement',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/acknowledgement',
            mandatory: false,
            sectionType: 'submission-form',
            collapsed: false,
            enabled: false,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          identifiers: {
            header: 'submit.progressbar.describe.identifiers',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/identifiers',
            mandatory: false,
            sectionType: 'submission-form',
            collapsed: false,
            enabled: false,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          references: {
            header: 'submit.progressbar.describe.references',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/references',
            mandatory: false,
            sectionType: 'submission-form',
            collapsed: false,
            enabled: false,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          upload: {
            header: 'submit.progressbar.upload',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload',
            mandatory: true,
            sectionType: 'upload',
            collapsed: false,
            enabled: true,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          license: {
            header: 'submit.progressbar.license',
            config: '',
            mandatory: true,
            sectionType: 'license',
            visibility: {
              main: null,
              other: 'READONLY',
            },
            collapsed: false,
            enabled: true,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
        },
        isLoading: false,
        savePending: false,
        depositPending: false,
      },
    },
  };
  const validSubState = {
    objects: {
      826: {
        collection: '43fe1f8c-09a6-4fcf-9c78-5d4fed8f2c8f',
        definition: 'traditional',
        selfUrl: 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826',
        activeSection: 'keyinformation',
        sections: {
          extraction: {
            config: '',
            mandatory: true,
            scope: SectionScope.Submission,
            sectionType: 'utils',
            visibility: {
              main: 'HIDDEN',
              other: 'HIDDEN',
            },
            collapsed: false,
            enabled: true,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          collection: {
            config: '',
            mandatory: true,
            scope: SectionScope.Submission,
            sectionType: 'collection',
            visibility: {
              main: 'HIDDEN',
              other: 'HIDDEN',
            },
            collapsed: false,
            enabled: true,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          keyinformation: {
            header: 'submit.progressbar.describe.keyinformation',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/keyinformation',
            mandatory: true,
            sectionType: 'submission-form',
            collapsed: false,
            enabled: true,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: true,
          },
          indexing: {
            header: 'submit.progressbar.describe.indexing',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/indexing',
            mandatory: false,
            sectionType: 'submission-form',
            collapsed: false,
            enabled: false,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          publicationchannel: {
            header: 'submit.progressbar.describe.publicationchannel',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/publicationchannel',
            mandatory: true,
            sectionType: 'submission-form',
            collapsed: false,
            enabled: true,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: true,
          },
          acknowledgement: {
            header: 'submit.progressbar.describe.acknowledgement',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/acknowledgement',
            mandatory: false,
            sectionType: 'submission-form',
            collapsed: false,
            enabled: false,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          identifiers: {
            header: 'submit.progressbar.describe.identifiers',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/identifiers',
            mandatory: false,
            sectionType: 'submission-form',
            collapsed: false,
            enabled: false,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          references: {
            header: 'submit.progressbar.describe.references',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/references',
            mandatory: false,
            sectionType: 'submission-form',
            collapsed: false,
            enabled: false,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: false,
          },
          upload: {
            header: 'submit.progressbar.upload',
            config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload',
            mandatory: true,
            sectionType: 'upload',
            collapsed: false,
            enabled: true,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: true,
          },
          license: {
            header: 'submit.progressbar.license',
            config: '',
            mandatory: true,
            sectionType: 'license',
            visibility: {
              main: null,
              other: 'READONLY',
            },
            collapsed: false,
            enabled: true,
            data: {},
            errorsToShow: [],
            serverValidationErrors: [],
            isLoading: false,
            isValid: true,
          },
        },
        isLoading: false,
        savePending: false,
        depositPending: false,
      },
    },
  };
  const restService = new SubmissionRestServiceStub();
  const router = new RouterMock();
  const selfUrl = 'https://rest.api/dspace-spring-rest/api/submission/workspaceitems/826';
  const submissionDefinition: any = mockSubmissionDefinition;
  const submissionJsonPatchOperationsService = new SubmissionJsonPatchOperationsServiceStub();

  let scheduler: TestScheduler;
  let service: SubmissionService;

  const searchService = getMockSearchService();

  const requestServce = getMockRequestService();

  beforeEach(waitForAsync(() => {

    TestBed.configureTestingModule({
      imports: [
        StoreModule.forRoot({ submissionReducers } as any, storeModuleConfig),
        TranslateModule.forRoot({
          loader: {
            provide: TranslateLoader,
            useClass: TranslateLoaderMock,
          },
        }),
      ],
      providers: [
        { provide: Router, useValue: router },
        { provide: SubmissionRestService, useValue: restService },
        { provide: ActivatedRoute, useValue: new MockActivatedRoute() },
        { provide: SearchService, useValue: searchService },
        { provide: RequestService, useValue: requestServce },
        { provide: SubmissionJsonPatchOperationsService, useValue: submissionJsonPatchOperationsService },
        NotificationsService,
        RouteService,
        SubmissionService,
        TranslateService,
      ],
    }).compileComponents();
  }));

  beforeEach(() => {
    service = TestBed.inject(SubmissionService);
    spyOn((service as any).store, 'dispatch').and.callThrough();
  });

  describe('changeSubmissionCollection', () => {
    it('should dispatch a new ChangeSubmissionCollectionAction', () => {
      service.changeSubmissionCollection(submissionId, collectionId);
      const expected = new ChangeSubmissionCollectionAction(submissionId, collectionId);

      expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
    });
  });

  describe('createSubmission', () => {
    it('should create a new submission', () => {
      service.createSubmission();

      expect((service as any).restService.postToEndpoint).toHaveBeenCalled();
      expect((service as any).restService.postToEndpoint).toHaveBeenCalledWith('workspaceitems', {}, null, null, undefined);
    });

    it('should create a new submission with collection', () => {
      service.createSubmission(collectionId);

      expect((service as any).restService.postToEndpoint).toHaveBeenCalled();
      expect((service as any).restService.postToEndpoint).toHaveBeenCalledWith('workspaceitems', {}, null, null, collectionId);
    });
  });

  describe('createSubmissionFromExternalSource', () => {
    it('should deposit submission', () => {
      const options: HttpOptions = Object.create({});
      let headers = new HttpHeaders();
      headers = headers.append('Content-Type', 'text/uri-list');
      options.headers = headers;

      service.createSubmissionFromExternalSource(selfUrl, collectionId);

      expect((service as any).restService.postToEndpoint).toHaveBeenCalledWith('workspaceitems', selfUrl, null, options, collectionId);
    });
  });

  describe('depositSubmission', () => {
    it('should deposit submission', () => {
      const options: HttpOptions = Object.create({});
      let headers = new HttpHeaders();
      headers = headers.append('Content-Type', 'text/uri-list');
      options.headers = headers;

      service.depositSubmission(selfUrl);

      expect((service as any).restService.postToEndpoint).toHaveBeenCalledWith('workflowitems', selfUrl, null, options);
    });
  });

  describe('discardSubmission', () => {
    it('should discard submission', () => {
      service.discardSubmission('826');

      expect((service as any).restService.deleteById).toHaveBeenCalledWith('826');
    });
  });

  describe('dispatchInit', () => {
    it('should dispatch a new InitSubmissionFormAction', () => {
      service.dispatchInit(
        collectionId,
        submissionId,
        selfUrl,
        submissionDefinition,
        {},
        new Item(),
        null,
      );
      const expected = new InitSubmissionFormAction(
        collectionId,
        submissionId,
        selfUrl,
        submissionDefinition,
        {},
        new Item(),
        null);

      expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
    });
  });

  describe('dispatchDeposit', () => {
    it('should dispatch a new SaveAndDepositSubmissionAction', () => {
      service.dispatchDeposit(submissionId);
      const expected = new SaveAndDepositSubmissionAction(submissionId);

      expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
    });
  });

  describe('dispatchDiscard', () => {
    it('should dispatch a new DiscardSubmissionAction', () => {
      service.dispatchDiscard(submissionId);
      const expected = new DiscardSubmissionAction(submissionId);

      expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
    });
  });

  describe('dispatchSave', () => {
    it('should dispatch a new SaveSubmissionFormAction', () => {
      service.dispatchSave(submissionId);
      const expected = new SaveSubmissionFormAction(submissionId);

      expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
    });

    it('should dispatch a new SaveSubmissionFormAction with manual flag', () => {
      service.dispatchSave(submissionId, true);
      const expected = new SaveSubmissionFormAction(submissionId, true);

      expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
    });
  });

  describe('dispatchSaveForLater', () => {
    it('should dispatch a new SaveForLaterSubmissionFormAction', () => {
      service.dispatchSaveForLater(submissionId);
      const expected = new SaveForLaterSubmissionFormAction(submissionId);

      expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
    });
  });

  describe('dispatchSaveSection', () => {
    it('should dispatch a new SaveSubmissionSectionFormAction', () => {
      service.dispatchSaveSection(submissionId, sectionId);
      const expected = new SaveSubmissionSectionFormAction(submissionId, sectionId);

      expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
    });
  });

  describe('getSubmissionObject', () => {
    it('should return submission object state from the store', () => {
      spyOn((service as any).store, 'select').and.returnValue(hot('a', {
        a: subState.objects[826],
      }));

      const result = service.getSubmissionObject('826');
      const expected = cold('b', { b: subState.objects[826] });

      expect(result).toBeObservable(expected);
    });
  });

  describe('getActiveSectionId', () => {
    it('should return current active submission form section', () => {
      spyOn((service as any).store, 'select').and.returnValue(hot('a', {
        a: subState.objects[826],
      }));

      const result = service.getActiveSectionId('826');
      const expected = cold('b', { b: 'keyinformation' });

      expect(result).toBeObservable(expected);

    });
  });

  describe('getSubmissionSections', () => {
    it('should return submission form sections', () => {
      spyOn(service, 'getSubmissionScope').and.returnValue(SubmissionScopeType.WorkspaceItem);
      spyOn((service as any).store, 'select').and.returnValue(hot('a|', {
        a: subState.objects[826],
      }));

      const result = service.getSubmissionSections('826');
      const expected = cold('(bc|)', {
        b: [],
        c:
          [
            {
              header: 'submit.progressbar.describe.keyinformation',
              id: 'keyinformation',
              config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/keyinformation',
              mandatory: true,
              sectionType: 'submission-form',
              data: {},
              errorsToShow: [],
              serverValidationErrors: [],
            },
            {
              header: 'submit.progressbar.describe.indexing',
              id: 'indexing',
              config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/indexing',
              mandatory: false,
              sectionType: 'submission-form',
              data: {},
              errorsToShow: [],
              serverValidationErrors: [],
            },
            {
              header: 'submit.progressbar.describe.publicationchannel',
              id: 'publicationchannel',
              config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/publicationchannel',
              mandatory: true,
              sectionType: 'submission-form',
              data: {},
              errorsToShow: [],
              serverValidationErrors: [],
            },
            {
              header: 'submit.progressbar.describe.acknowledgement',
              id: 'acknowledgement',
              config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/acknowledgement',
              mandatory: false,
              sectionType: 'submission-form',
              data: {},
              errorsToShow: [],
              serverValidationErrors: [],
            },
            {
              header: 'submit.progressbar.describe.identifiers',
              id: 'identifiers',
              config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/identifiers',
              mandatory: false,
              sectionType: 'submission-form',
              data: {},
              errorsToShow: [],
              serverValidationErrors: [],
            },
            {
              header: 'submit.progressbar.describe.references',
              id: 'references',
              config: 'https://rest.api/dspace-spring-rest/api/config/submissionforms/references',
              mandatory: false,
              sectionType: 'submission-form',
              data: {},
              errorsToShow: [],
              serverValidationErrors: [],
            },
            {
              header: 'submit.progressbar.upload',
              id: 'upload',
              config: 'https://rest.api/dspace-spring-rest/api/config/submissionuploads/upload',
              mandatory: true,
              sectionType: 'upload',
              data: {},
              errorsToShow: [],
              serverValidationErrors: [],
            },
            {
              header: 'submit.progressbar.license',
              id: 'license',
              config: '',
              mandatory: true,
              sectionType: 'license',
              data: {},
              errorsToShow: [],
              serverValidationErrors: [],
            },
          ],
      });

      expect(result).toBeObservable(expected);
    });
  });

  describe('getDisabledSectionsList', () => {
    it('should return list of submission disabled sections', () => {
      spyOn((service as any).store, 'select').and.returnValue(hot('-a|', {
        a: subState.objects[826],
      }));

      const result = service.getDisabledSectionsList('826');
      const expected = cold('bc|', {
        b: [],
        c:
          [
            {
              header: 'submit.progressbar.describe.indexing',
              id: 'indexing',
            },
            {
              header: 'submit.progressbar.describe.acknowledgement',
              id: 'acknowledgement',
            },
            {
              header: 'submit.progressbar.describe.identifiers',
              id: 'identifiers',
            },
            {
              header: 'submit.progressbar.describe.references',
              id: 'references',
            },
          ],
      });

      expect(result).toBeObservable(expected);
    });
  });

  describe('getSubmissionObjectLinkName', () => {
    it('should return properly submission link name', () => {
      let expected = 'workspaceitems';
      router.setRoute('/workspaceitems/826/edit');
      expect(service.getSubmissionObjectLinkName()).toBe(expected);

      expected = 'workspaceitems';
      router.setRoute('/submit');
      expect(service.getSubmissionObjectLinkName()).toBe(expected);

      expected = 'workflowitems';
      router.setRoute('/workflowitems/826/edit');
      expect(service.getSubmissionObjectLinkName()).toBe(expected);

      expected = 'edititems';
      router.setRoute('/items/9e79b1f2-ae0f-4737-9a4b-990952a8857c/edit');
      expect(service.getSubmissionObjectLinkName()).toBe(expected);
    });
  });

  describe('getSubmissionScope', () => {
    it('should return properly submission scope', () => {
      let expected = SubmissionScopeType.WorkspaceItem;

      router.setRoute('/workspaceitems/826/edit');
      expect(service.getSubmissionScope()).toBe(expected);

      router.setRoute('/submit');
      expect(service.getSubmissionScope()).toBe(expected);

      expected = SubmissionScopeType.WorkflowItem;
      router.setRoute('/workflowitems/826/edit');
      expect(service.getSubmissionScope()).toBe(expected);

    });
  });

  describe('getSubmissionStatus', () => {
    it('should return properly submission status', () => {
      spyOn(service, 'getSubmissionScope').and.returnValue(SubmissionScopeType.WorkspaceItem);
      spyOn((service as any).store, 'select').and.returnValue(hot('-a-b', {
        a: subState,
        b: validSubState,
      }));
      const result = service.getSubmissionStatus('826');
      const expected = cold('cc-d', {
        c: false,
        d: true,
      });

      expect(result).toBeObservable(expected);
    });
  });

  describe('getSubmissionSaveProcessingStatus', () => {
    it('should return submission save processing status', () => {
      spyOn((service as any).store, 'select').and.returnValue(hot('-a', {
        a: subState.objects[826],
      }));

      const result = service.getSubmissionSaveProcessingStatus('826');
      const expected = cold('bb', {
        b: false,
      });

      expect(result).toBeObservable(expected);
    });
  });

  describe('getSubmissionDepositProcessingStatus', () => {
    it('should return submission deposit processing status', () => {
      spyOn((service as any).store, 'select').and.returnValue(hot('-a', {
        a: subState.objects[826],
      }));

      const result = service.getSubmissionDepositProcessingStatus('826');
      const expected = cold('bb', {
        b: false,
      });

      expect(result).toBeObservable(expected);
    });
  });

  describe('hasUnsavedModification', () => {
    it('should call jsonPatchOperationService hasPendingOperation observable', () => {
      (service as any).jsonPatchOperationService.hasPendingOperations = jasmine.createSpy('hasPendingOperations')
        .and.returnValue(observableOf(true));

      scheduler = getTestScheduler();
      scheduler.schedule(() => service.hasUnsavedModification());
      scheduler.flush();

      expect((service as any).jsonPatchOperationService.hasPendingOperations).toHaveBeenCalledWith('sections');

    });
  });

  describe('isSectionHidden', () => {
    describe('when submission scope is workspace', () => {
      beforeEach(() => {
        spyOn(service, 'getSubmissionScope').and.returnValue(SubmissionScopeType.WorkspaceItem);
      });

      describe('and section scope is workspace', () => {
        it('should return true when visibility main is HIDDEN and visibility other is null', () => {
          let section: any = {
            scope: SectionScope.Submission,
            visibility: {
              main: 'HIDDEN',
              other: null,
            },
          };
          expect(service.isSectionHidden(section)).toBeTrue();
        });
        it('should return true when both visibility main and other are HIDDEN', () => {
          let section: any = {
            scope: SectionScope.Submission,
            visibility: {
              main: 'HIDDEN',
              other: 'HIDDEN',
            },
          };
          expect(service.isSectionHidden(section)).toBeTrue();
        });
        it('should return false when visibility main is null and visibility other is HIDDEN', () => {
          let section: any = {
            scope: SectionScope.Submission,
            visibility: {
              main: null,
              other: 'HIDDEN',
            },
          };
          expect(service.isSectionHidden(section)).toBeFalse();
        });
        it('should return false when visibility is null', () => {
          let section: any = {
            scope: SectionScope.Submission,
            visibility: null,
          };
          expect(service.isSectionHidden(section)).toBeFalse();
        });
      });

      describe('and section scope is workflow', () => {
        it('should return false when visibility main is HIDDEN and visibility other is null', () => {
          let section: any = {
            scope: SectionScope.Workflow,
            visibility: {
              main: 'HIDDEN',
              other: null,
            },
          };
          expect(service.isSectionHidden(section)).toBeFalse();
        });
        it('should return true when both visibility main and other are HIDDEN', () => {
          let section: any = {
            scope: SectionScope.Workflow,
            visibility: {
              main: 'HIDDEN',
              other: 'HIDDEN',
            },
          };
          expect(service.isSectionHidden(section)).toBeTrue();
        });
        it('should return true when visibility main is null and visibility other is HIDDEN', () => {
          let section: any = {
            scope: SectionScope.Workflow,
            visibility: {
              main: null,
              other: 'HIDDEN',
            },
          };
          expect(service.isSectionHidden(section)).toBeTrue();
        });
        it('should return false when visibility is null', () => {
          let section: any = {
            scope: SectionScope.Workflow,
            visibility: null,
          };
          expect(service.isSectionHidden(section)).toBeFalse();
        });
      });

      describe('and section scope is null', () => {
        it('should return false', () => {
          let section: any = {
            scope: null,
            visibility: {
              main: 'HIDDEN',
              other: null,
            },
          };
          expect(service.isSectionHidden(section)).toBeFalse();
        });
      });

    });

    describe('when submission scope is workflow', () => {
      beforeEach(() => {
        spyOn(service, 'getSubmissionScope').and.returnValue(SubmissionScopeType.WorkflowItem);
      });

      describe('and section scope is workspace', () => {
        it('should return false when visibility main is HIDDEN and visibility other is null', () => {
          let section: any = {
            scope: SectionScope.Submission,
            visibility: {
              main: 'HIDDEN',
              other: null,
            },
          };
          expect(service.isSectionHidden(section)).toBeFalse();
        });
        it('should return true when both visibility main and other are HIDDEN', () => {
          let section: any = {
            scope: SectionScope.Submission,
            visibility: {
              main: 'HIDDEN',
              other: 'HIDDEN',
            },
          };
          expect(service.isSectionHidden(section)).toBeTrue();
        });
        it('should return true when visibility main is null and visibility other is HIDDEN', () => {
          let section: any = {
            scope: SectionScope.Submission,
            visibility: {
              main: null,
              other: 'HIDDEN',
            },
          };
          expect(service.isSectionHidden(section)).toBeTrue();
        });
        it('should return false when visibility is null', () => {
          let section: any = {
            scope: SectionScope.Submission,
            visibility: null,
          };
          expect(service.isSectionHidden(section)).toBeFalse();
        });
      });

      describe('and section scope is workflow', () => {
        it('should return true when visibility main is HIDDEN and visibility other is null', () => {
          let section: any = {
            scope: SectionScope.Workflow,
            visibility: {
              main: 'HIDDEN',
              other: null,
            },
          };
          expect(service.isSectionHidden(section)).toBeTrue();
        });
        it('should return true when both visibility main and other are HIDDEN', () => {
          let section: any = {
            scope: SectionScope.Workflow,
            visibility: {
              main: 'HIDDEN',
              other: 'HIDDEN',
            },
          };
          expect(service.isSectionHidden(section)).toBeTrue();
        });
        it('should return false when visibility main is null and visibility other is HIDDEN', () => {
          let section: any = {
            scope: SectionScope.Workflow,
            visibility: {
              main: null,
              other: 'HIDDEN',
            },
          };
          expect(service.isSectionHidden(section)).toBeFalse();
        });
        it('should return false when visibility is null', () => {
          let section: any = {
            scope: SectionScope.Workflow,
            visibility: null,
          };
          expect(service.isSectionHidden(section)).toBeFalse();
        });
      });

      describe('and section scope is null', () => {
        it('should return false', () => {
          let section: any = {
            scope: null,
            visibility: {
              main: 'HIDDEN',
              other: null,
            },
          };
          expect(service.isSectionHidden(section)).toBeFalse();
        });
      });

    });


  });

  describe('isSubmissionLoading', () => {
    it('should return true/false when section is loading/not loading', () => {
      const spy = spyOn(service, 'getSubmissionObject').and.returnValue(observableOf({ isLoading: true }));

      let expected = cold('(b|)', {
        b: true,
      });

      expect(service.isSubmissionLoading(submissionId)).toBeObservable(expected);

      spy.and.returnValue(observableOf({ isLoading: false }));

      expected = cold('(b|)', {
        b: false,
      });

      expect(service.isSubmissionLoading(submissionId)).toBeObservable(expected);
    });
  });

  describe('notifyNewSection', () => {
    it('should return true/false when section is loading/not loading', fakeAsync(() => {
      spyOn((service as any).translate, 'get').and.returnValue(observableOf('test'));

      spyOn((service as any).notificationsService, 'info');

      service.notifyNewSection(submissionId, sectionId);
      flush();

      expect((service as any).notificationsService.info).toHaveBeenCalledWith(null, 'submission.sections.general.metadata-extracted-new-section', null, true);
    }));
  });

  describe('redirectToMyDSpace', () => {
    it('should redirect to MyDspace page', () => {
      scheduler = getTestScheduler();
      const spy = spyOn((service as any).routeService, 'getPreviousUrl');

      spy.and.returnValue(observableOf('/mydspace?configuration=workflow'));
      scheduler.schedule(() => service.redirectToMyDSpace());
      scheduler.flush();

      expect((service as any).router.navigateByUrl).toHaveBeenCalledWith('/mydspace?configuration=workflow');

      spy.and.returnValue(observableOf(''));
      scheduler.schedule(() => service.redirectToMyDSpace());
      scheduler.flush();

      expect((service as any).router.navigate).toHaveBeenCalledWith(['/mydspace']);

      spy.and.returnValue(observableOf('/home'));
      scheduler.schedule(() => service.redirectToMyDSpace());
      scheduler.flush();

      expect((service as any).router.navigate).toHaveBeenCalledWith(['/mydspace']);
    });
  });

  describe('resetAllSubmissionObjects', () => {
    it('should dispatch a new CancelSubmissionFormAction', () => {
      service.resetAllSubmissionObjects();
      const expected = new CancelSubmissionFormAction();

      expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
    });
  });

  describe('resetSubmissionObject', () => {
    it('should dispatch a new ResetSubmissionFormAction', () => {
      service.resetSubmissionObject(
        collectionId,
        submissionId,
        selfUrl,
        submissionDefinition,
        {},
        new Item(),
      )
      ;
      const expected = new ResetSubmissionFormAction(
        collectionId,
        submissionId,
        selfUrl,
        {},
        submissionDefinition,
        new Item(),
      );

      expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
    });
  });

  describe('retrieveSubmission', () => {
    it('should retrieve submission from REST endpoint', () => {
      (service as any).restService.getDataById.and.returnValue(hot('a|', {
        a: mockSubmissionRestResponse,
      }));

      const result = service.retrieveSubmission('826');
      const expected = cold('(b|)', {
        b: jasmine.objectContaining({ payload: mockSubmissionRestResponse[0] }),
      });

      expect(result).toBeObservable(expected);
    });

    it('should catch error from REST endpoint', () => {
      const requestError = new RequestError('Internal Server Error');
      requestError.statusCode = 500;
      const errorResponse = new ErrorResponse(requestError);

      (service as any).restService.getDataById.and.callFake(
        () => observableThrowError(errorResponse),
      );

      service.retrieveSubmission('826').subscribe((r) => {
        const expectedRD = createFailedRemoteDataObject('Internal Server Error',500) as any;
        expect(r.payload).toEqual(expectedRD.payload);
        expect(r.statusCode).toEqual(expectedRD.statusCode);
        expect(r.errorMessage).toEqual(expectedRD.errorMessage);
        expect(r.hasSucceeded).toEqual(expectedRD.hasSucceeded);
      });
    });
  });

  describe('setActiveSection', () => {
    it('should dispatch a new SetActiveSectionAction', () => {
      service.setActiveSection(submissionId, sectionId);
      const expected = new SetActiveSectionAction(submissionId, sectionId);

      expect((service as any).store.dispatch).toHaveBeenCalledWith(expected);
    });
  });

  describe('startAutoSave', () => {

    let environmentAutoSaveTimerOriginalValue;

    beforeEach(() => {
      environmentAutoSaveTimerOriginalValue = environment.submission.autosave.timer;
    });

    it('should start Auto Save', fakeAsync(() => {
      const duration = environment.submission.autosave.timer;

      service.startAutoSave('826');
      const sub = (service as any).timer$.subscribe();

      tick(duration / 2);
      expect((service as any).store.dispatch).not.toHaveBeenCalled();

      tick(duration / 2);
      expect((service as any).store.dispatch).toHaveBeenCalled();

      sub.unsubscribe();
      (service as any).autoSaveSub.unsubscribe();
    }));

    it('should not start Auto Save if timer is 0', fakeAsync(() => {
      environment.submission.autosave.timer = 0;

      service.startAutoSave('826');

      expect((service as any).autoSaveSub).toBeUndefined();
    }));

    afterEach(() => {
      environment.submission.autosave.timer = environmentAutoSaveTimerOriginalValue;
    });

  });

  describe('stopAutoSave', () => {
    it('should stop Auto Save', () => {
      service.startAutoSave('826');
      service.stopAutoSave();

      expect((service as any).autoSaveSub).toBeNull();
    });
  });
});