import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ActivatedRoute } from '@angular/router';
import { FlightNumberSearchPageComponent } from '@online-board/pages/search/flight-number-search/flight-number-search-page.component';
import { OnlineBoardDataSourceService } from '@online-board/services/data-source.service';
import { OnlineBoardFilterService } from '@online-board/services/filter/filter.service';
import { getOnlineBoardFilterServiceMock } from '@online-board/services/filter/filter.service.mock';
import {
    IDetailsPageNavigationParams,
    OnlineBoardNavigationService,
} from '@online-board/services/navigation.service';
import { OnlineBoardRequestBuilderService } from '@online-board/services/request/request-builder.service';
import {
    ONLINE_BOARD_URL_BASE,
    OnlineBoardUrlBuilderService,
} from '@online-board/services/url';
import { IOnlineBoardRouteData } from '@online-board/types';
import { ApiParserService } from '@shared/services/api/parser.service';
import { OnlineBoardFiltersStateService } from '@shared/services/filters/online-board-filters-state.service';
import { areSame } from '@utils/date';
import FlightDateUtils from '@utils/flight/date';
import { BehaviorSubject } from 'rxjs';

describe('FlightNumberSearchPageComponent', () => {
    let component: FlightNumberSearchPageComponent;
    let fixture: ComponentFixture<FlightNumberSearchPageComponent>;
    let filtersStateService: OnlineBoardFiltersStateService;

    let getFlightDateMock;

    const routeData: IOnlineBoardRouteData = {
        urlParams: {},
    };

    const loadFlightsByFlightNumberMock = jasmine.createSpy(
        'loadFlightsByFlightNumber',
    );
    const stopLoadingMock = jasmine.createSpy('stopLoading');
    const toFlightNumberPageMock = jasmine.createSpy('toFlightNumberPage');
    const toDetailsPageMock = jasmine.createSpy('toDetailsPage');
    const baseUrl = 'onlineboard';

    beforeEach(async () => {
        await TestBed.configureTestingModule({
            declarations: [FlightNumberSearchPageComponent],
            providers: [
                OnlineBoardRequestBuilderService,
                OnlineBoardUrlBuilderService,
                ApiParserService,
                OnlineBoardFiltersStateService,
                {
                    provide: OnlineBoardDataSourceService,
                    useValue: {
                        loadFlightsByFlightNumber:
                            loadFlightsByFlightNumberMock,
                        stopLoading: stopLoadingMock,
                    },
                },
                {
                    provide: ActivatedRoute,
                    useValue: {
                        data: new BehaviorSubject(routeData),
                    },
                },
                {
                    provide: OnlineBoardNavigationService,
                    useValue: {
                        toFlightNumberPage: toFlightNumberPageMock,
                        toDetailsPage: toDetailsPageMock,
                    },
                },
                {
                    provide: ONLINE_BOARD_URL_BASE,
                    useValue: baseUrl,
                },
                {
                    provide: OnlineBoardFilterService,
                    useValue: getOnlineBoardFilterServiceMock(),
                },
            ],
            schemas: [NO_ERRORS_SCHEMA],
        }).compileComponents();
    });

    beforeEach(() => {
        fixture = TestBed.createComponent(FlightNumberSearchPageComponent);
        component = fixture.componentInstance;
        filtersStateService = TestBed.inject(OnlineBoardFiltersStateService);
        routeData.urlParams = {
            flightNumber: {
                date: new Date(2022, 4, 28),
                flightNumber: '0001',
                carrier: 'SU',
            },
        };
        getFlightDateMock = spyOn(FlightDateUtils, 'getFlightDate');

        loadFlightsByFlightNumberMock.calls.reset();
        stopLoadingMock.calls.reset();
        toFlightNumberPageMock.calls.reset();
        toDetailsPageMock.calls.reset();
    });

    it('should set selected tab in filters service on init', () => {
        expect(filtersStateService.selectedTab).toBe('route');
        component.ngOnInit();
        expect(filtersStateService.selectedTab).toBe('flight');
    });

    it('should set params to params provided by route.data', () => {
        expect(component.searchDate).toBe(undefined);
        component.ngOnInit();
        expect(
            areSame(
                component.searchDate,
                routeData.urlParams.flightNumber.date,
            ),
        ).toBe(true);
    });

    it('should not call loadFlightsByFlightNumber if urlParams were not provided', () => {
        routeData.urlParams = undefined;
        component.ngOnInit();
        expect(loadFlightsByFlightNumberMock).not.toHaveBeenCalled();
    });

    it('should not call loadFlightsByFlightNumber there is no flightNumber field in urlParams', () => {
        routeData.urlParams = {};
        component.ngOnInit();
        expect(loadFlightsByFlightNumberMock).not.toHaveBeenCalled();
    });

    it('should load flights with params provided by route data', () => {
        component.ngOnInit();
        expect(loadFlightsByFlightNumberMock).toHaveBeenCalledWith(
            routeData.urlParams.flightNumber,
        );

        component.handleSameUrlNavigation();
        expect(loadFlightsByFlightNumberMock).toHaveBeenCalledTimes(2);
        expect(loadFlightsByFlightNumberMock).toHaveBeenCalledWith(
            routeData.urlParams.flightNumber,
        );
    });

    it('should call dataSource.stopLoading', () => {
        component.handleRequestCancellation();
        expect(stopLoadingMock).toHaveBeenCalled();
    });

    it('should navigate to flight number page with provided date and correct flight id', () => {
        component.ngOnInit();
        const date = new Date(2022, 4, 20);
        component.handleDateChange(date);

        expect(toFlightNumberPageMock).toHaveBeenCalledWith({
            flightNumber: '0001',
            carrier: 'SU',
            date,
        });
    });

    it('should navigate to details page with correct flight id, date and request', () => {
        component.ngOnInit();

        const request = `${baseUrl}-flight-SU0001-20220528`;
        const { date } = routeData.urlParams.flightNumber;
        const flightId = {
            flightNumber: '0002',
            carrier: 'SU',
            date: '',
        };
        getFlightDateMock.withArgs({ flightId }).and.returnValue(date);

        component.navigateToDetails({ flightId } as any);
        const { args } = toDetailsPageMock.calls.mostRecent();
        expect(args.length).toBe(1);
        const navigationParams: IDetailsPageNavigationParams = args[0];

        expect(navigationParams.request).toBe(request);
        expect(areSame(navigationParams.date, date)).toBe(true);
        expect(navigationParams.flightId).toEqual(flightId);
    });
});
