import { TestBed } from '@angular/core/testing';
import { CrmCustomerService } from '@domain/crm';
import { Result } from '@domain/defs';
import { AutocompleteDTO, CustomerInfoDTO, CustomerService, InputDTO, InputOptionsDTO, PayerService } from '@swagger/crm';
import { of } from 'rxjs';
import { take } from 'rxjs/operators';

describe('CrmCustomerService', () => {
  let service: CrmCustomerService;
  let customerService: jasmine.SpyObj<CustomerService>;
  let payerService: jasmine.SpyObj<PayerService>;

  const testQueryString = 'Unit Test';

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        {
          provide: CustomerService,
          useValue: jasmine.createSpyObj('customerService', [
            'CustomerCustomerAutocomplete',
            'CustomerListCustomers',
            'CustomerQueryCustomerFilter',
          ]),
        },
        {
          provide: PayerService,
          useValue: jasmine.createSpyObj('payerService', ['PayerCreatePayer', 'PayerUpdatePayer', 'PayerGetPayer']),
        },
      ],
    });

    service = TestBed.inject(CrmCustomerService);
    customerService = TestBed.inject(CustomerService) as any;
    payerService = TestBed.inject(PayerService) as any;
  });

  it('should be created', () => {
    expect(service instanceof CrmCustomerService).toBeTruthy();
  });

  describe('complete', () => {
    const mockResponse: Result<AutocompleteDTO[]> = { result: [] };

    it('should call CustomerCustomerAutocomplete and return its result', async () => {
      customerService.CustomerCustomerAutocomplete.and.returnValue(of(mockResponse));

      const result = await service.complete(testQueryString).toPromise();

      expect(customerService.CustomerCustomerAutocomplete).toHaveBeenCalledWith({
        input: testQueryString,
        filter: {},
        take: 5,
      });

      expect(result).toEqual(mockResponse);
    });
  });

  describe('getCustomers', () => {
    const mockResponse: Result<CustomerInfoDTO[]> = { result: [] };

    it('it should call CustomerListCustomers and return its result', async () => {
      customerService.CustomerListCustomers.and.returnValue(of(mockResponse));

      const result = await service.getCustomers(testQueryString).toPromise();

      expect(customerService.CustomerListCustomers).toHaveBeenCalledWith({
        input: { qs: testQueryString },
        take: 20,
        skip: 0,
        filter: {},
      });
      expect(result).toEqual(mockResponse);
    });

    it('should set skip and take if provided', async () => {
      customerService.CustomerListCustomers.and.returnValue(of(mockResponse));

      const skipTest = 10;
      const takeTest = 100;

      const result = await service.getCustomers(testQueryString, { skip: skipTest, take: takeTest }).toPromise();

      expect(customerService.CustomerListCustomers).toHaveBeenCalledWith({
        input: { qs: testQueryString },
        take: takeTest,
        skip: skipTest,
        filter: {},
      });
      expect(result).toEqual(mockResponse);
    });
  });

  describe('getFilters', () => {
    const inputDtos: InputDTO[] = [{ type: 1, key: 'Test 1', options: ([] as unknown) as InputOptionsDTO }];

    beforeEach(() => {
      customerService.CustomerQueryCustomerFilter.and.returnValue(of({ result: inputDtos }));
    });
    it('should return the filters from the customer service', async () => {
      const result = await service.getFilters().toPromise();

      const expected = { result: inputDtos };

      expect(customerService.CustomerQueryCustomerFilter).toHaveBeenCalled();
      expect(result).toEqual(expected);
    });
  });
});
