import { TestBed } from '@angular/core/testing';
import { ActivatedRouteSnapshot, Router } from '@angular/router';
import { CanActivateScheduleRouteSearch } from '@schedule/guards/can-activate-schedule-route-search.service';
import { ScheduleDateValidationService } from '@schedule/services/date-validation.service';
import { ScheduleRouteParamsValidationService } from '@schedule/services/route-params-validation.service';
import { SCHEDULE_URL_BASE } from '@schedule/services/url/url-base';
import { ScheduleUrlParserService } from '@schedule/services/url/url-parser.service';
import { AppSettingsService } from '@shared/services';
import { StationCodeValidationService } from '@shared/services/validators/station-code.service';

describe('CanActivateRouteSearch', () => {
    const scheduleMinDate = new Date(2022, 5, 1);
    const scheduleMaxDate = new Date(2022, 5, 31);
    const navigateByUrl = jasmine.createSpy('navigateByUrl');
    const navigate = jasmine.createSpy('navigate');
    const stationCodeValidationService: Partial<StationCodeValidationService> =
        {
            isStationCodeValid: (code: string) => {
                const res = code === 'MOW' || code === 'KUF';

                return Promise.resolve(res);
            },
        };

    let service: CanActivateScheduleRouteSearch;

    beforeEach(() => {
        TestBed.configureTestingModule({
            providers: [
                CanActivateScheduleRouteSearch,
                ScheduleUrlParserService,
                ScheduleRouteParamsValidationService,
                ScheduleDateValidationService,
                {
                    provide: StationCodeValidationService,
                    useValue: stationCodeValidationService,
                },
                {
                    provide: SCHEDULE_URL_BASE,
                    useValue: 'schedule',
                },
                {
                    provide: Router,
                    useValue: {
                        navigate,
                        navigateByUrl,
                    },
                },
                {
                    provide: AppSettingsService,
                    useValue: {
                        getSettings() {
                            return Promise.resolve({
                                scheduleMinDate,
                                scheduleMaxDate,
                            });
                        },
                    },
                },
            ],
        });

        service = TestBed.inject(CanActivateScheduleRouteSearch);
        navigateByUrl.calls.reset();
        navigate.calls.reset();
    });

    it('should return true', async () => {
        const route: Partial<ActivatedRouteSnapshot> = {
            params: {
                params: 'MOW-KUF-20220601-20220625-C0',
            },
        };

        const result = await service.canActivate(route as any);
        expect(result).toBe(true);
        expect(navigate).not.toHaveBeenCalled();
        expect(navigateByUrl).not.toHaveBeenCalled();
    });

    it('should redirect to not found', async () => {
        const route: Partial<ActivatedRouteSnapshot> = {
            params: {
                params: 'ABA-KUF-20220601-20220625-C0',
            },
        };

        const result = await service.canActivate(route as any);
        expect(result).not.toBe(true);
        expect(navigateByUrl).toHaveBeenCalledWith('/error/404');
        expect(navigate).not.toHaveBeenCalled();
    });

    it('should redirect to root', async () => {
        const route: Partial<ActivatedRouteSnapshot> = {
            params: {
                params: 'MOW-KUF-20220125-20220601-C0',
            },
        };

        const result = await service.canActivate(route as any);
        expect(result).not.toBe(true);
        expect(navigateByUrl).toHaveBeenCalledWith('schedule');
        expect(navigate).not.toHaveBeenCalled();
    });

    it('should redirect to root because of invalid range', async () => {
        const route: Partial<ActivatedRouteSnapshot> = {
            params: {
                params: 'MOW-KUF-20220107-20220601-C0',
            },
        };

        const result = await service.canActivate(route as any);
        expect(result).not.toBe(true);
        expect(navigateByUrl).toHaveBeenCalledWith('schedule');
        expect(navigate).not.toHaveBeenCalled();
    });

    it('should return true for search with return flights', async () => {
        const route: Partial<ActivatedRouteSnapshot> = {
            params: {
                params: 'MOW-KUF-20220601-20220625-C0',
                returnParams: 'MOW-KUF-20220601-20220625-C0',
            },
        };

        const result = await service.canActivate(route as any);
        expect(result).toBe(true);
        expect(navigate).not.toHaveBeenCalled();
        expect(navigateByUrl).not.toHaveBeenCalled();
    });

    it('should redirect to not found for search with return flights', async () => {
        const route: Partial<ActivatedRouteSnapshot> = {
            params: {
                params: 'MOW-KUF-20220601-20220625-C0',
                returnParams: 'ABA-KUF-20220614-20220629-C0',
            },
        };

        const result = await service.canActivate(route as any);
        expect(result).not.toBe(true);
        expect(navigateByUrl).toHaveBeenCalledWith('/error/404');
        expect(navigate).not.toHaveBeenCalled();
    });

    it('should redirect to root for search with return flights', async () => {
        const route: Partial<ActivatedRouteSnapshot> = {
            params: {
                params: 'MOW-KUF-20220614-20220625-C0',
                returnParams: 'MOW-KUF-20220120-20220601-C0',
            },
        };

        const result = await service.canActivate(route as any);
        expect(result).not.toBe(true);
        expect(navigateByUrl).toHaveBeenCalledWith('schedule');
        expect(navigate).not.toHaveBeenCalled();
    });

    it('should redirect to root because of invalid range in return route', async () => {
        const route: Partial<ActivatedRouteSnapshot> = {
            params: {
                params: 'MOW-KUF-20220601-20220625-C0',
                returnParams: 'MOW-KUF-20220626-20220614-C0',
            },
        };

        const result = await service.canActivate(route as any);
        expect(result).not.toBe(true);
        expect(navigateByUrl).toHaveBeenCalledWith('schedule');
        expect(navigate).not.toHaveBeenCalled();
    });

    it('should redirect to root because first return date is less than first date', async () => {
        const route: Partial<ActivatedRouteSnapshot> = {
            params: {
                params: 'MOW-KUF-20220614-20220620-C0',
                returnParams: 'MOW-KUF-20220601-20220625-C0',
            },
        };

        const result = await service.canActivate(route as any);
        expect(result).not.toBe(true);
        expect(navigateByUrl).toHaveBeenCalledWith('schedule');
        expect(navigate).not.toHaveBeenCalled();
    });

    it('should redirect to root because second return date is less than second date', async () => {
        const route: Partial<ActivatedRouteSnapshot> = {
            params: {
                params: 'MOW-KUF-20220614-20220620-C0',
                returnParams: 'MOW-KUF-20220616-20220619-C0',
            },
        };

        const result = await service.canActivate(route as any);
        expect(result).not.toBe(true);
        expect(navigateByUrl).toHaveBeenCalledWith('schedule');
        expect(navigate).not.toHaveBeenCalled();
    });

    it('should activate route when first date is less than min schedule date but in one week with min date', async () => {
        const route: Partial<ActivatedRouteSnapshot> = {
            params: {
                params: 'MOW-KUF-20220530-20220620-C0',
            },
        };

        const result = await service.canActivate(route as any);
        expect(result).toBe(true);
        expect(navigateByUrl).not.toHaveBeenCalled();
        expect(navigate).not.toHaveBeenCalled();
    });

    it('should activate route when last date is more than max schedule date but in one week with max date', async () => {
        const route: Partial<ActivatedRouteSnapshot> = {
            params: {
                params: 'MOW-KUF-20220614-20220703-C0',
            },
        };

        const result = await service.canActivate(route as any);
        expect(result).toBe(true);
        expect(navigateByUrl).not.toHaveBeenCalled();
        expect(navigate).not.toHaveBeenCalled();
    });
});
