import { TestBed } from '@angular/core/testing';
import { DictionariesService } from '@modules/components/page-filters/services/dictionaries-service';
import { ScheduleRouteParamsValidationService } from '@schedule/services/route-params-validation.service';
import { IScheduleRouteDirectionParams } from '@schedule/services/url/types';
import { AppSettingsService } from '@shared/services';
import { StationCodeValidationService } from '@shared/services/validators/station-code.service';

describe('ScheduleRouteParamsValidationService', () => {
    let service: ScheduleRouteParamsValidationService;
    const scheduleMinDate = new Date(2022, 4, 1);
    const scheduleMaxDate = new Date(2022, 4, 31);
    const dictionariesService: Partial<DictionariesService> = {
        ready$: Promise.resolve(),
        getCityOrAirport(code: string) {
            const map = new Map();
            map.set('MOW', true);
            map.set('LED', true);
            map.set('KZN', true);
            map.set('KUF', true);
            map.set('ABA', true);
            map.set('SVO', true);

            return map.has(code) as any;
        },
    };

    const defaultParams: IScheduleRouteDirectionParams = {
        dateFrom: new Date(2022, 4, 4),
        dateTo: new Date(2022, 4, 11),
        departure: 'MOW',
        arrival: 'LED',
    };
    const defaultReturnParams: IScheduleRouteDirectionParams = {
        dateFrom: new Date(2022, 4, 15),
        dateTo: new Date(2022, 4, 27),
        departure: 'LED',
        arrival: 'MOW',
    };

    beforeEach(() => {
        TestBed.configureTestingModule({
            providers: [
                ScheduleRouteParamsValidationService,
                StationCodeValidationService,
                {
                    provide: DictionariesService,
                    useValue: dictionariesService,
                },
                {
                    provide: AppSettingsService,
                    useValue: {
                        getSettings: () => {
                            return Promise.resolve({
                                scheduleMinDate,
                                scheduleMaxDate,
                            });
                        },
                    },
                },
            ],
        });

        service = TestBed.inject(ScheduleRouteParamsValidationService);
    });

    it('should accept params', async () => {
        let result = await service.validateRoute(defaultParams);
        expect(result.isValid).toBe(true);

        result = await service.validateRoute(
            defaultParams,
            defaultReturnParams,
        );
        expect(result.isValid).toBe(true);

        result = await service.validateRoute(defaultParams, {
            ...defaultReturnParams,
            dateFrom: new Date(2022, 4, 3),
        });
        expect(result.isValid).toBe(true);
    });

    it('should reject date params because date from is less than minimum schedule date', async () => {
        const params: IScheduleRouteDirectionParams = {
            ...defaultParams,
            dateFrom: new Date(2022, 3, 20),
        };

        const result = await service.validateRoute(params);
        expect(result.isValid).toBe(false);
        expect(result.areDatesValid).toBe(false);
    });

    it('should reject date params because date to is more than maximum schedule date', async () => {
        const params: IScheduleRouteDirectionParams = {
            ...defaultParams,
            dateTo: new Date(2022, 5, 10),
        };

        const result = await service.validateRoute(params);
        expect(result.isValid).toBe(false);
        expect(result.areDatesValid).toBe(false);
    });

    it('should reject date params because return date from is less than minimum schedule date', async () => {
        const returnParams: IScheduleRouteDirectionParams = {
            ...defaultReturnParams,
            dateFrom: new Date(2022, 3, 20),
        };

        const result = await service.validateRoute(defaultParams, returnParams);
        expect(result.isValid).toBe(false);
        expect(result.areDatesValid).toBe(false);
    });

    it('should reject date params because return date to is more than maximum schedule date', async () => {
        const returnParams: IScheduleRouteDirectionParams = {
            ...defaultReturnParams,
            dateTo: new Date(2022, 5, 10),
        };

        const result = await service.validateRoute(defaultParams, returnParams);
        expect(result.isValid).toBe(false);
        expect(result.areDatesValid).toBe(false);
    });

    it('should reject date params because date to is less than date from', async () => {
        const params: IScheduleRouteDirectionParams = {
            ...defaultParams,
            dateFrom: new Date(2022, 4, 20),
            dateTo: new Date(2022, 4, 10),
        };

        const result = await service.validateRoute(params);
        expect(result.isValid).toBe(false);
        expect(result.areDatesValid).toBe(false);
    });

    it('should reject date params because return date to is less than return date from', async () => {
        const returnParams: IScheduleRouteDirectionParams = {
            ...defaultReturnParams,
            dateFrom: new Date(2022, 4, 20),
            dateTo: new Date(2022, 4, 10),
        };

        const result = await service.validateRoute(defaultParams, returnParams);
        expect(result.isValid).toBe(false);
        expect(result.areDatesValid).toBe(false);
    });

    it('should reject date params because return date from is less than return date from', async () => {
        const returnParams: IScheduleRouteDirectionParams = {
            ...defaultReturnParams,
            dateFrom: new Date(2022, 4, 1),
        };

        const result = await service.validateRoute(defaultParams, returnParams);
        expect(result.isValid).toBe(false);
        expect(result.areDatesValid).toBe(false);
    });

    it('should reject date params because only one return date was provided', async () => {
        let returnParams: IScheduleRouteDirectionParams = {
            ...defaultReturnParams,
            dateFrom: undefined,
        };

        let result = await service.validateRoute(defaultParams, returnParams);
        expect(result.isValid).toBe(false);
        expect(result.areDatesValid).toBe(false);

        returnParams = {
            ...defaultReturnParams,
            dateTo: undefined,
        };

        result = await service.validateRoute(defaultParams, returnParams);
        expect(result.isValid).toBe(false);
        expect(result.areDatesValid).toBe(false);
    });

    it('should reject date params because date to is more than return date to', async () => {
        const params: IScheduleRouteDirectionParams = {
            ...defaultParams,
            dateTo: new Date(2022, 4, 28),
        };

        const result = await service.validateRoute(params, defaultReturnParams);
        expect(result.isValid).toBe(false);
        expect(result.areDatesValid).toBe(false);
    });

    it('should reject station params because arrival is invalid', async () => {
        const params: IScheduleRouteDirectionParams = {
            ...defaultParams,
            arrival: 'FFF',
        };

        const result = await service.validateRoute(params, defaultReturnParams);
        expect(result.isValid).toBe(false);
        expect(result.areStationsValid).toBe(false);
    });

    it('should reject station params because return arrival is invalid', async () => {
        const returnParams: IScheduleRouteDirectionParams = {
            ...defaultReturnParams,
            arrival: 'FFF',
        };

        const result = await service.validateRoute(defaultParams, returnParams);
        expect(result.isValid).toBe(false);
        expect(result.areStationsValid).toBe(false);
    });

    it('should reject station params because departure is invalid', async () => {
        const params: IScheduleRouteDirectionParams = {
            ...defaultParams,
            departure: 'FFF',
        };

        const result = await service.validateRoute(params, defaultReturnParams);
        expect(result.isValid).toBe(false);
        expect(result.areStationsValid).toBe(false);
    });

    it('should reject station params because return departure is invalid', async () => {
        const returnParams: IScheduleRouteDirectionParams = {
            ...defaultReturnParams,
            departure: 'FFF',
        };

        const result = await service.validateRoute(defaultParams, returnParams);
        expect(result.isValid).toBe(false);
        expect(result.areStationsValid).toBe(false);
    });

    it('should reject time range', async () => {
        const params: IScheduleRouteDirectionParams = {
            ...defaultParams,
            timeFrom: '1200',
            timeTo: '0600',
        };

        const result = await service.validateRoute(params, defaultReturnParams);
        expect(result.isValid).toBe(false);
        expect(result.isTimeRangeValid).toBe(false);
    });

    it('should reject return time range', async () => {
        const returnParams: IScheduleRouteDirectionParams = {
            ...defaultReturnParams,
            timeFrom: '1200',
            timeTo: '0600',
        };

        const result = await service.validateRoute(defaultParams, returnParams);
        expect(result.isValid).toBe(false);
        expect(result.isTimeRangeValid).toBe(false);
    });
});
