import { TestBed } from '@angular/core/testing';
import { Observable, of } from 'rxjs';
import { provideMockActions } from '@ngrx/effects/testing';
import { provideMockStore } from '@ngrx/store/testing';
import { OrderService, ResponseArgsOfHistoryDTO, StrictHttpResponse } from '@swagger/oms';
import { hot, cold } from 'jasmine-marbles';
import * as actions from './history.actions';
import { HistoryEffects } from './history.effects';
import { HttpHeaders } from '@angular/common/http';
import { TypedAction } from '@ngrx/store/src/models';
import { HistoryDTO } from '@cmf/trade-api';
import { OrderHistoryStatus } from '@shelf-store/defs';

fdescribe('HistoryEffects', () => {
  let historyEffects: HistoryEffects;
  let actions$: Observable<any>;
  let orderService: jasmine.SpyObj<OrderService>;

  const id = 123;
  const httpResponse: StrictHttpResponse<ResponseArgsOfHistoryDTO> = {
    body: ({
      result: [
        {
          id: 456,
          name: 'HistoryDTO Name',
          values: [],
        },
      ],
      error: false,
    } as unknown) as ResponseArgsOfHistoryDTO,
    ok: true,
    type: null,
    clone: null,
    headers: new HttpHeaders(),
    status: 200,
    statusText: 'Okay',
    url: 'someRandomUrl.de',
  };

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        HistoryEffects,
        provideMockStore({}),
        {
          provide: OrderService,
          useValue: jasmine.createSpyObj('orderService', ['OrderGetOrderItemStatusHistoryResponse']),
        },
        provideMockActions(() => actions$),
      ],
    });

    historyEffects = TestBed.inject(HistoryEffects);
    orderService = TestBed.inject(OrderService);
  });

  describe('initHistory$', () => {
    it('should dispatch fetchHistory', () => {
      const initHistoryAction = actions.initOrderHistory({ id });

      const initHistory$ = hot('-a', { a: initHistoryAction });
      actions$ = initHistory$;

      const fetchHistory$ = actions.fetchHistory({ id });
      const expected$ = cold('-b', { b: fetchHistory$ });

      expect(historyEffects.initHistory$).toBeObservable(expected$);
    });
  });

  describe('fetchHistory$', () => {
    let fetchHistoryAction: {
      id: number;
    } & TypedAction<string>;
    let fetchHistoryDoneAction: {
      id: number;
      response: StrictHttpResponse<ResponseArgsOfHistoryDTO>;
    } & TypedAction<any>;

    beforeEach(() => {
      orderService.OrderGetOrderItemStatusHistoryResponse.and.returnValue(of(httpResponse));

      fetchHistoryAction = actions.fetchHistory({ id });

      fetchHistoryDoneAction = actions.fetchHistoryDone({
        id,
        response: httpResponse,
      });
    });

    it('should call the orderService OrderGetOrderItemStatusHistoryResponse', () => {
      const fetchHistory$ = hot('a', { a: fetchHistoryAction });

      actions$ = fetchHistory$;

      const expected$ = cold('b', { b: fetchHistoryDoneAction });

      expect(historyEffects.fetchHistory$).toBeObservable(expected$);

      expect(orderService.OrderGetOrderItemStatusHistoryResponse).toHaveBeenCalledWith({ orderItemSubsetId: id });
    });

    it('should dispatch fetchHistoryDone', () => {
      const fetchHistory$ = hot('-a', { a: fetchHistoryAction });

      actions$ = fetchHistory$;

      const expected$ = cold('-b', { b: fetchHistoryDoneAction });

      expect(historyEffects.fetchHistory$).toBeObservable(expected$);

      expect(orderService.OrderGetOrderItemStatusHistoryResponse).toHaveBeenCalled();
    });
  });

  describe('fetchHistoryDone$', () => {
    let fetchHistoryDoneAction: {
      id: number;
      response: StrictHttpResponse<ResponseArgsOfHistoryDTO>;
    } & TypedAction<string>;
    let addOrderHistoryAction: {
      id: number;
      histories: HistoryDTO[];
    } & TypedAction<string>;

    beforeEach(() => {
      addOrderHistoryAction = actions.addOrderHistory({
        id,
        histories: (httpResponse.body.result as unknown) as HistoryDTO[],
      });
    });

    it('should dispatch addOrderHistory if the response is ok', () => {
      fetchHistoryDoneAction = actions.fetchHistoryDone({
        id,
        response: httpResponse,
      });

      const fetchHistoryDone$ = hot('-a', { a: fetchHistoryDoneAction });
      actions$ = fetchHistoryDone$;

      const expected$ = cold('-b', { b: addOrderHistoryAction });

      expect(historyEffects.fetchHistoryDone$).toBeObservable(expected$);
    });
    it('should dispatch a status change to error', () => {
      fetchHistoryDoneAction = actions.fetchHistoryDone({
        id,
        response: { ...httpResponse, ok: false } as StrictHttpResponse<ResponseArgsOfHistoryDTO>,
      });

      const fetchHistoryDone$ = hot('-a', { a: fetchHistoryDoneAction });
      actions$ = fetchHistoryDone$;

      const setStatus$ = actions.setStatus({
        id,
        status: OrderHistoryStatus.ERROR,
      });
      const expected$ = cold('-b', { b: setStatus$ });

      expect(historyEffects.fetchHistoryDone$).toBeObservable(expected$);
    });
  });
});
