import { ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpResponse } from '@angular/common/http';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { FormBuilder } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { of, Subject, from } from 'rxjs';

import { IVariable } from 'app/entities/variable/variable.model';
import { VariableService } from 'app/entities/variable/service/variable.service';
import { IPeriod } from 'app/entities/period/period.model';
import { PeriodService } from 'app/entities/period/service/period.service';
import { IPeriodVersion } from 'app/entities/period-version/period-version.model';
import { PeriodVersionService } from 'app/entities/period-version/service/period-version.service';
import { IUnit } from 'app/entities/unit/unit.model';
import { UnitService } from 'app/entities/unit/service/unit.service';
import { IOrganization } from 'app/entities/organization/organization.model';
import { OrganizationService } from 'app/entities/organization/service/organization.service';
import { IInputDataUpload } from 'app/entities/input-data-upload/input-data-upload.model';
import { InputDataUploadService } from 'app/entities/input-data-upload/service/input-data-upload.service';
import { IInputData } from '../input-data.model';
import { InputDataService } from '../service/input-data.service';
import { InputDataFormService } from './input-data-form.service';

import { InputDataUpdateComponent } from './input-data-update.component';

describe('InputData Management Update Component', () => {
  let comp: InputDataUpdateComponent;
  let fixture: ComponentFixture<InputDataUpdateComponent>;
  let activatedRoute: ActivatedRoute;
  let inputDataFormService: InputDataFormService;
  let inputDataService: InputDataService;
  let variableService: VariableService;
  let periodService: PeriodService;
  let periodVersionService: PeriodVersionService;
  let unitService: UnitService;
  let organizationService: OrganizationService;
  let inputDataUploadService: InputDataUploadService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule, InputDataUpdateComponent],
      providers: [
        FormBuilder,
        {
          provide: ActivatedRoute,
          useValue: {
            params: from([{}]),
          },
        },
      ],
    })
      .overrideTemplate(InputDataUpdateComponent, '')
      .compileComponents();

    fixture = TestBed.createComponent(InputDataUpdateComponent);
    activatedRoute = TestBed.inject(ActivatedRoute);
    inputDataFormService = TestBed.inject(InputDataFormService);
    inputDataService = TestBed.inject(InputDataService);
    variableService = TestBed.inject(VariableService);
    periodService = TestBed.inject(PeriodService);
    periodVersionService = TestBed.inject(PeriodVersionService);
    unitService = TestBed.inject(UnitService);
    organizationService = TestBed.inject(OrganizationService);
    inputDataUploadService = TestBed.inject(InputDataUploadService);

    comp = fixture.componentInstance;
  });

  describe('ngOnInit', () => {
    it('Should call InputData query and add missing value', () => {
      const inputData: IInputData = { id: 456 };
      const sourceInputData: IInputData = { id: 27513 };
      inputData.sourceInputData = sourceInputData;

      const inputDataCollection: IInputData[] = [{ id: 3796 }];
      jest.spyOn(inputDataService, 'query').mockReturnValue(of(new HttpResponse({ body: inputDataCollection })));
      const additionalInputData = [sourceInputData];
      const expectedCollection: IInputData[] = [...additionalInputData, ...inputDataCollection];
      jest.spyOn(inputDataService, 'addInputDataToCollectionIfMissing').mockReturnValue(expectedCollection);

      activatedRoute.data = of({ inputData });
      comp.ngOnInit();

      expect(inputDataService.query).toHaveBeenCalled();
      expect(inputDataService.addInputDataToCollectionIfMissing).toHaveBeenCalledWith(
        inputDataCollection,
        ...additionalInputData.map(expect.objectContaining),
      );
      expect(comp.inputDataSharedCollection).toEqual(expectedCollection);
    });

    it('Should call Variable query and add missing value', () => {
      const inputData: IInputData = { id: 456 };
      const variable: IVariable = { id: 25598 };
      inputData.variable = variable;

      const variableCollection: IVariable[] = [{ id: 4654 }];
      jest.spyOn(variableService, 'query').mockReturnValue(of(new HttpResponse({ body: variableCollection })));
      const additionalVariables = [variable];
      const expectedCollection: IVariable[] = [...additionalVariables, ...variableCollection];
      jest.spyOn(variableService, 'addVariableToCollectionIfMissing').mockReturnValue(expectedCollection);

      activatedRoute.data = of({ inputData });
      comp.ngOnInit();

      expect(variableService.query).toHaveBeenCalled();
      expect(variableService.addVariableToCollectionIfMissing).toHaveBeenCalledWith(
        variableCollection,
        ...additionalVariables.map(expect.objectContaining),
      );
      expect(comp.variablesSharedCollection).toEqual(expectedCollection);
    });

    it('Should call Period query and add missing value', () => {
      const inputData: IInputData = { id: 456 };
      const period: IPeriod = { id: 30428 };
      inputData.period = period;

      const periodCollection: IPeriod[] = [{ id: 25867 }];
      jest.spyOn(periodService, 'query').mockReturnValue(of(new HttpResponse({ body: periodCollection })));
      const additionalPeriods = [period];
      const expectedCollection: IPeriod[] = [...additionalPeriods, ...periodCollection];
      jest.spyOn(periodService, 'addPeriodToCollectionIfMissing').mockReturnValue(expectedCollection);

      activatedRoute.data = of({ inputData });
      comp.ngOnInit();

      expect(periodService.query).toHaveBeenCalled();
      expect(periodService.addPeriodToCollectionIfMissing).toHaveBeenCalledWith(
        periodCollection,
        ...additionalPeriods.map(expect.objectContaining),
      );
      expect(comp.periodsSharedCollection).toEqual(expectedCollection);
    });

    it('Should call PeriodVersion query and add missing value', () => {
      const inputData: IInputData = { id: 456 };
      const periodVersion: IPeriodVersion = { id: 28923 };
      inputData.periodVersion = periodVersion;

      const periodVersionCollection: IPeriodVersion[] = [{ id: 30543 }];
      jest.spyOn(periodVersionService, 'query').mockReturnValue(of(new HttpResponse({ body: periodVersionCollection })));
      const additionalPeriodVersions = [periodVersion];
      const expectedCollection: IPeriodVersion[] = [...additionalPeriodVersions, ...periodVersionCollection];
      jest.spyOn(periodVersionService, 'addPeriodVersionToCollectionIfMissing').mockReturnValue(expectedCollection);

      activatedRoute.data = of({ inputData });
      comp.ngOnInit();

      expect(periodVersionService.query).toHaveBeenCalled();
      expect(periodVersionService.addPeriodVersionToCollectionIfMissing).toHaveBeenCalledWith(
        periodVersionCollection,
        ...additionalPeriodVersions.map(expect.objectContaining),
      );
      expect(comp.periodVersionsSharedCollection).toEqual(expectedCollection);
    });

    it('Should call Unit query and add missing value', () => {
      const inputData: IInputData = { id: 456 };
      const sourceUnit: IUnit = { id: 17465 };
      inputData.sourceUnit = sourceUnit;
      const unit: IUnit = { id: 19595 };
      inputData.unit = unit;

      const unitCollection: IUnit[] = [{ id: 32254 }];
      jest.spyOn(unitService, 'query').mockReturnValue(of(new HttpResponse({ body: unitCollection })));
      const additionalUnits = [sourceUnit, unit];
      const expectedCollection: IUnit[] = [...additionalUnits, ...unitCollection];
      jest.spyOn(unitService, 'addUnitToCollectionIfMissing').mockReturnValue(expectedCollection);

      activatedRoute.data = of({ inputData });
      comp.ngOnInit();

      expect(unitService.query).toHaveBeenCalled();
      expect(unitService.addUnitToCollectionIfMissing).toHaveBeenCalledWith(
        unitCollection,
        ...additionalUnits.map(expect.objectContaining),
      );
      expect(comp.unitsSharedCollection).toEqual(expectedCollection);
    });

    it('Should call Organization query and add missing value', () => {
      const inputData: IInputData = { id: 456 };
      const owner: IOrganization = { id: 28415 };
      inputData.owner = owner;

      const organizationCollection: IOrganization[] = [{ id: 31358 }];
      jest.spyOn(organizationService, 'query').mockReturnValue(of(new HttpResponse({ body: organizationCollection })));
      const additionalOrganizations = [owner];
      const expectedCollection: IOrganization[] = [...additionalOrganizations, ...organizationCollection];
      jest.spyOn(organizationService, 'addOrganizationToCollectionIfMissing').mockReturnValue(expectedCollection);

      activatedRoute.data = of({ inputData });
      comp.ngOnInit();

      expect(organizationService.query).toHaveBeenCalled();
      expect(organizationService.addOrganizationToCollectionIfMissing).toHaveBeenCalledWith(
        organizationCollection,
        ...additionalOrganizations.map(expect.objectContaining),
      );
      expect(comp.organizationsSharedCollection).toEqual(expectedCollection);
    });

    it('Should call InputDataUpload query and add missing value', () => {
      const inputData: IInputData = { id: 456 };
      const sourceInputDataUpload: IInputDataUpload = { id: 31895 };
      inputData.sourceInputDataUpload = sourceInputDataUpload;

      const inputDataUploadCollection: IInputDataUpload[] = [{ id: 29460 }];
      jest.spyOn(inputDataUploadService, 'query').mockReturnValue(of(new HttpResponse({ body: inputDataUploadCollection })));
      const additionalInputDataUploads = [sourceInputDataUpload];
      const expectedCollection: IInputDataUpload[] = [...additionalInputDataUploads, ...inputDataUploadCollection];
      jest.spyOn(inputDataUploadService, 'addInputDataUploadToCollectionIfMissing').mockReturnValue(expectedCollection);

      activatedRoute.data = of({ inputData });
      comp.ngOnInit();

      expect(inputDataUploadService.query).toHaveBeenCalled();
      expect(inputDataUploadService.addInputDataUploadToCollectionIfMissing).toHaveBeenCalledWith(
        inputDataUploadCollection,
        ...additionalInputDataUploads.map(expect.objectContaining),
      );
      expect(comp.inputDataUploadsSharedCollection).toEqual(expectedCollection);
    });

    it('Should update editForm', () => {
      const inputData: IInputData = { id: 456 };
      const sourceInputData: IInputData = { id: 6255 };
      inputData.sourceInputData = sourceInputData;
      const variable: IVariable = { id: 17285 };
      inputData.variable = variable;
      const period: IPeriod = { id: 29501 };
      inputData.period = period;
      const periodVersion: IPeriodVersion = { id: 10417 };
      inputData.periodVersion = periodVersion;
      const sourceUnit: IUnit = { id: 4773 };
      inputData.sourceUnit = sourceUnit;
      const unit: IUnit = { id: 14051 };
      inputData.unit = unit;
      const owner: IOrganization = { id: 16657 };
      inputData.owner = owner;
      const sourceInputDataUpload: IInputDataUpload = { id: 3116 };
      inputData.sourceInputDataUpload = sourceInputDataUpload;

      activatedRoute.data = of({ inputData });
      comp.ngOnInit();

      expect(comp.inputDataSharedCollection).toContain(sourceInputData);
      expect(comp.variablesSharedCollection).toContain(variable);
      expect(comp.periodsSharedCollection).toContain(period);
      expect(comp.periodVersionsSharedCollection).toContain(periodVersion);
      expect(comp.unitsSharedCollection).toContain(sourceUnit);
      expect(comp.unitsSharedCollection).toContain(unit);
      expect(comp.organizationsSharedCollection).toContain(owner);
      expect(comp.inputDataUploadsSharedCollection).toContain(sourceInputDataUpload);
      expect(comp.inputData).toEqual(inputData);
    });
  });

  describe('save', () => {
    it('Should call update service on save for existing entity', () => {
      // GIVEN
      const saveSubject = new Subject<HttpResponse<IInputData>>();
      const inputData = { id: 123 };
      jest.spyOn(inputDataFormService, 'getInputData').mockReturnValue(inputData);
      jest.spyOn(inputDataService, 'update').mockReturnValue(saveSubject);
      jest.spyOn(comp, 'previousState');
      activatedRoute.data = of({ inputData });
      comp.ngOnInit();

      // WHEN
      comp.save();
      expect(comp.isSaving).toEqual(true);
      saveSubject.next(new HttpResponse({ body: inputData }));
      saveSubject.complete();

      // THEN
      expect(inputDataFormService.getInputData).toHaveBeenCalled();
      expect(comp.previousState).toHaveBeenCalled();
      expect(inputDataService.update).toHaveBeenCalledWith(expect.objectContaining(inputData));
      expect(comp.isSaving).toEqual(false);
    });

    it('Should call create service on save for new entity', () => {
      // GIVEN
      const saveSubject = new Subject<HttpResponse<IInputData>>();
      const inputData = { id: 123 };
      jest.spyOn(inputDataFormService, 'getInputData').mockReturnValue({ id: null });
      jest.spyOn(inputDataService, 'create').mockReturnValue(saveSubject);
      jest.spyOn(comp, 'previousState');
      activatedRoute.data = of({ inputData: null });
      comp.ngOnInit();

      // WHEN
      comp.save();
      expect(comp.isSaving).toEqual(true);
      saveSubject.next(new HttpResponse({ body: inputData }));
      saveSubject.complete();

      // THEN
      expect(inputDataFormService.getInputData).toHaveBeenCalled();
      expect(inputDataService.create).toHaveBeenCalled();
      expect(comp.isSaving).toEqual(false);
      expect(comp.previousState).toHaveBeenCalled();
    });

    it('Should set isSaving to false on error', () => {
      // GIVEN
      const saveSubject = new Subject<HttpResponse<IInputData>>();
      const inputData = { id: 123 };
      jest.spyOn(inputDataService, 'update').mockReturnValue(saveSubject);
      jest.spyOn(comp, 'previousState');
      activatedRoute.data = of({ inputData });
      comp.ngOnInit();

      // WHEN
      comp.save();
      expect(comp.isSaving).toEqual(true);
      saveSubject.error('This is an error!');

      // THEN
      expect(inputDataService.update).toHaveBeenCalled();
      expect(comp.isSaving).toEqual(false);
      expect(comp.previousState).not.toHaveBeenCalled();
    });
  });

  describe('Compare relationships', () => {
    describe('compareInputData', () => {
      it('Should forward to inputDataService', () => {
        const entity = { id: 123 };
        const entity2 = { id: 456 };
        jest.spyOn(inputDataService, 'compareInputData');
        comp.compareInputData(entity, entity2);
        expect(inputDataService.compareInputData).toHaveBeenCalledWith(entity, entity2);
      });
    });

    describe('compareVariable', () => {
      it('Should forward to variableService', () => {
        const entity = { id: 123 };
        const entity2 = { id: 456 };
        jest.spyOn(variableService, 'compareVariable');
        comp.compareVariable(entity, entity2);
        expect(variableService.compareVariable).toHaveBeenCalledWith(entity, entity2);
      });
    });

    describe('comparePeriod', () => {
      it('Should forward to periodService', () => {
        const entity = { id: 123 };
        const entity2 = { id: 456 };
        jest.spyOn(periodService, 'comparePeriod');
        comp.comparePeriod(entity, entity2);
        expect(periodService.comparePeriod).toHaveBeenCalledWith(entity, entity2);
      });
    });

    describe('comparePeriodVersion', () => {
      it('Should forward to periodVersionService', () => {
        const entity = { id: 123 };
        const entity2 = { id: 456 };
        jest.spyOn(periodVersionService, 'comparePeriodVersion');
        comp.comparePeriodVersion(entity, entity2);
        expect(periodVersionService.comparePeriodVersion).toHaveBeenCalledWith(entity, entity2);
      });
    });

    describe('compareUnit', () => {
      it('Should forward to unitService', () => {
        const entity = { id: 123 };
        const entity2 = { id: 456 };
        jest.spyOn(unitService, 'compareUnit');
        comp.compareUnit(entity, entity2);
        expect(unitService.compareUnit).toHaveBeenCalledWith(entity, entity2);
      });
    });

    describe('compareOrganization', () => {
      it('Should forward to organizationService', () => {
        const entity = { id: 123 };
        const entity2 = { id: 456 };
        jest.spyOn(organizationService, 'compareOrganization');
        comp.compareOrganization(entity, entity2);
        expect(organizationService.compareOrganization).toHaveBeenCalledWith(entity, entity2);
      });
    });

    describe('compareInputDataUpload', () => {
      it('Should forward to inputDataUploadService', () => {
        const entity = { id: 123 };
        const entity2 = { id: 456 };
        jest.spyOn(inputDataUploadService, 'compareInputDataUpload');
        comp.compareInputDataUpload(entity, entity2);
        expect(inputDataUploadService.compareInputDataUpload).toHaveBeenCalledWith(entity, entity2);
      });
    });
  });
});
