import { createStateResource, StateResource } from '@alfa-client/tech-shared';
import { Mock, mock } from '@alfa-client/test-utils';
import { TestBed } from '@angular/core/testing';
import { expect } from '@jest/globals';
import { singleCold, singleColdCompleted } from 'libs/tech-shared/test/marbles';
import { Observable, of } from 'rxjs';
import {
  createAggregationMapping,
  createAggregationMappingListResource,
  createAggregationMappingResource,
} from '../../test/aggregation-mapping';
import { AggregationMappingListResourceService } from './aggregation-mapping-list-resource.service';
import { AggregationMappingResourceService } from './aggregation-mapping-resource.service';
import { AggregationMapping, AggregationMappingListResource, AggregationMappingResource } from './aggregation-mapping.model';
import { AggregationMappingService } from './aggregation-mapping.service';

describe('AggregationMappingService', () => {
  let service: AggregationMappingService;
  let listResourceService: Mock<AggregationMappingListResourceService>;
  let resourceService: Mock<AggregationMappingResourceService>;

  beforeEach(() => {
    listResourceService = mock(AggregationMappingListResourceService);
    resourceService = mock(AggregationMappingResourceService);

    TestBed.configureTestingModule({
      providers: [
        AggregationMappingService,
        { provide: AggregationMappingListResourceService, useValue: listResourceService },
        { provide: AggregationMappingResourceService, useValue: resourceService },
      ],
    });

    service = TestBed.inject(AggregationMappingService);
  });

  it('should create', () => {
    expect(service).toBeTruthy();
  });

  describe('get list', () => {
    const aggregationMappingListResource: AggregationMappingListResource = createAggregationMappingListResource();
    const aggregationMappingListStateResource: StateResource<AggregationMappingListResource> =
      createStateResource(aggregationMappingListResource);

    beforeEach(() => {
      listResourceService.getList = jest.fn().mockReturnValue(singleCold(aggregationMappingListStateResource));
    });

    it('should call listResourceService', () => {
      service.getList();

      expect(listResourceService.getList).toHaveBeenCalled();
    });

    it('should return value', () => {
      const loadedAggregationMappingListResource: Observable<StateResource<AggregationMappingListResource>> = service.getList();

      expect(loadedAggregationMappingListResource).toBeObservable(singleCold(aggregationMappingListStateResource));
    });
  });

  describe('create', () => {
    const aggregationMappingResource: AggregationMappingResource = createAggregationMappingResource();
    const aggregationMappingStateResource: StateResource<AggregationMappingResource> =
      createStateResource(aggregationMappingResource);

    const aggregationMapping: AggregationMapping = createAggregationMapping();

    beforeEach(() => {
      listResourceService.create = jest.fn().mockReturnValue(singleCold(aggregationMappingStateResource));
    });

    it('should call resourceService', () => {
      service.create(aggregationMapping);

      expect(listResourceService.create).toHaveBeenCalledWith(aggregationMapping);
    });

    it('should return value', () => {
      const loadedAggregationMappingResource: Observable<StateResource<AggregationMappingResource>> =
        service.create(aggregationMapping);

      expect(loadedAggregationMappingResource).toBeObservable(singleCold(aggregationMappingStateResource));
    });
  });

  describe('refresh list', () => {
    it('should call list resource service', () => {
      listResourceService.refresh = jest.fn();

      service.refreshList();

      expect(listResourceService.refresh).toHaveBeenCalled();
    });
  });

  describe('get', () => {
    const stateResource: StateResource<AggregationMappingResource> = createStateResource(createAggregationMappingResource());

    beforeEach(() => {
      resourceService.get = jest.fn().mockReturnValue(of(stateResource));
    });

    it('should call resource service', () => {
      service.get();

      expect(resourceService.get).toHaveBeenCalled();
    });

    it('should emit resource', () => {
      const stateResource$: Observable<StateResource<AggregationMappingResource>> = service.get();

      expect(stateResource$).toBeObservable(singleColdCompleted(stateResource));
    });
  });

  describe('save', () => {
    const aggregationMapping: AggregationMapping = createAggregationMapping();
    const stateResource: StateResource<AggregationMappingResource> = createStateResource(createAggregationMappingResource());
    beforeEach(() => {
      resourceService.save = jest.fn().mockReturnValue(of(stateResource));
    });

    it('should call resource service', () => {
      service.save(aggregationMapping);

      expect(resourceService.save).toHaveBeenCalledWith(aggregationMapping);
    });

    it('should emit saved state resource', () => {
      const saved$: Observable<StateResource<AggregationMappingResource>> = service.save(aggregationMapping);

      expect(saved$).toBeObservable(singleColdCompleted(stateResource));
    });
  });
});