import { TestBed } from '@angular/core/testing';
import { RefreshService } from '@online-board/pages/flight-details/services/refresh.service';
import { OnlineBoardDataSourceService } from '@online-board/services/data-source.service';
import { APP_SETTINGS } from '@shared/services';
import { FlightStatus } from '@typings/enums';
import { IParsedFlightId } from '@typings/flight/flight-id';

describe('RefreshService', () => {
    let service: RefreshService;
    let dataSource: OnlineBoardDataSourceService;

    const refreshInterval = 100;

    const unsubscribeMock = jasmine.createSpy('unsubscribe');
    const loadFlightByFlightNumberMock = jasmine.createSpy(
        'loadFlightByFlightNumber',
    );

    const params: IParsedFlightId = {
        flightNumber: '0001',
        carrier: 'SU',
        date: new Date(2022, 4, 28),
    };

    beforeEach(() => {
        TestBed.configureTestingModule({
            providers: [
                RefreshService,
                {
                    provide: APP_SETTINGS,
                    useValue: {
                        refreshInterval,
                    },
                },
                {
                    provide: OnlineBoardDataSourceService,
                    useValue: {
                        loadFlightByFlightNumber: loadFlightByFlightNumberMock,
                    },
                },
            ],
        });

        unsubscribeMock.calls.reset();
        loadFlightByFlightNumberMock.calls.reset();

        service = TestBed.inject(RefreshService);
        dataSource = TestBed.inject(OnlineBoardDataSourceService);
    });

    beforeEach(() => {
        jasmine.clock().install();
    });

    afterEach(() => {
        jasmine.clock().uninstall();
    });

    it('should call loadFlightByFlightNumber with provided params each 100 seconds', () => {
        service.start(params);
        jasmine.clock().tick(refreshInterval);

        expect(loadFlightByFlightNumberMock).toHaveBeenCalledWith(params, true);

        jasmine.clock().tick(refreshInterval);
        expect(loadFlightByFlightNumberMock).toHaveBeenCalledTimes(2);

        jasmine.clock().tick(refreshInterval);
        expect(loadFlightByFlightNumberMock).toHaveBeenCalledTimes(3);
    });

    it('should unsubscribe if there is running interval', () => {
        (service.updateInterval as any) = {
            unsubscribe: unsubscribeMock,
        };

        service.start(params);
        expect(unsubscribeMock).toHaveBeenCalled();
    });

    it('should unsubscribe', () => {
        expect(() => service.stop()).not.toThrowError();

        (service.updateInterval as any) = {
            unsubscribe: unsubscribeMock,
        };
        service.stop();

        expect(unsubscribeMock).toHaveBeenCalled();
    });

    it('should call loadFlightByFlightNumber because flight has appropriate status', () => {
        (dataSource.flight as any) = { status: FlightStatus.IN_FLIGHT };

        service.start(params);
        jasmine.clock().tick(refreshInterval);
        expect(loadFlightByFlightNumberMock).toHaveBeenCalledWith(params, true);
        service.stop();

        (dataSource.flight as any) = { status: FlightStatus.SENT };

        service.start(params);
        jasmine.clock().tick(refreshInterval);
        expect(loadFlightByFlightNumberMock).toHaveBeenCalledTimes(2);

        const [first, second] =
            loadFlightByFlightNumberMock.calls.mostRecent().args;
        expect(first).toEqual(params);
        expect(second).toBe(true);
        service.stop();
    });

    it('should not call loadFlightByFlightNumber because flight has not appropriate status', () => {
        (dataSource.flight as any) = { status: FlightStatus.CANCELLED };

        service.start(params);
        jasmine.clock().tick(refreshInterval);
        expect(loadFlightByFlightNumberMock).not.toHaveBeenCalled();
        service.stop();
    });
});
