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

describe('ScheduleFilterValidationService', () => {
    let service: ScheduleFilterValidationService;

    beforeEach(() => {
        TestBed.configureTestingModule({
            providers: [
                ScheduleFilterValidationService,
                StationCodeValidationService,
                {
                    provide: DictionariesService,
                    useValue: getDictionariesServiceMock(),
                },
            ],
        });

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

    it('should return false because departure station is not provided', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {};

        const result = await service.validate({
            outbound: outbound as any,
        });
        expect(result).toBe(false);
        expect(service.departureError).toBe('SHARED.DEPARTURE-CITY-ERROR');
    });

    it('should return false because departure station is invalid', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'KUF',
        };

        const result = await service.validate({
            outbound: outbound as any,
        });
        expect(result).toBe(false);
        expect(service.departureError).toBe('SHARED.DEPARTURE-CITY-ERROR');
    });

    it('should return false because arrival station is not provided', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
        };

        const result = await service.validate({
            outbound: outbound as any,
        });
        expect(result).toBe(false);
        expect(service.arrivalError).toBe('SHARED.ARRIVAL-CITY-ERROR');
    });

    it('should return false because arrival station is invalid', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
            arrival: 'KUF',
        };

        const result = await service.validate({
            outbound: outbound as any,
        });
        expect(result).toBe(false);
        expect(service.arrivalError).toBe('SHARED.ARRIVAL-CITY-ERROR');
    });

    it('should return false because stations are equal', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
            arrival: 'MOW',
        };

        const result = await service.validate({
            outbound: outbound as any,
        });
        expect(result).toBe(false);
        expect(service.departureError).toBe(
            'SHARED.ARRIVAL-EQUALS-DEPARTURE-ERROR',
        );
    });

    it('should return false because dateFrom is not provided', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
            arrival: 'GDX',
        };

        const result = await service.validate({
            outbound: outbound as any,
        });
        expect(result).toBe(false);
        expect(service.dateRangeError).toBe('SHARED.WEEK_FORMAT-WRONG');
    });

    it('should return false because dateFrom is invalid', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
            arrival: 'GDX',
            dateFrom: new Date('invalid'),
        };

        const result = await service.validate({
            outbound: outbound as any,
        });
        expect(result).toBe(false);
        expect(service.dateRangeError).toBe('SHARED.WEEK_FORMAT-WRONG');
    });

    it('should return false because dateTo is not provided', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
            arrival: 'GDX',
            dateFrom: new Date(2022, 4, 28),
        };

        const result = await service.validate({
            outbound: outbound as any,
        });
        expect(result).toBe(false);
        expect(service.dateRangeError).toBe('SHARED.WEEK_FORMAT-WRONG');
    });

    it('should return false because dateTo is invalid', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
            arrival: 'GDX',
            dateFrom: new Date(2022, 4, 28),
            dateTo: new Date('invalid'),
        };

        const result = await service.validate({
            outbound: outbound as any,
        });
        expect(result).toBe(false);
        expect(service.dateRangeError).toBe('SHARED.WEEK_FORMAT-WRONG');
    });

    it('should return false because inbound dateFrom is not provided', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
            arrival: 'GDX',
            dateFrom: new Date(2022, 4, 28),
            dateTo: new Date(2022, 4, 29),
        };

        const inbound: Partial<IScheduleRouteDirectionParams> = {};

        const result = await service.validate({
            outbound: outbound as any,
            inbound: inbound as any,
        });
        expect(result).toBe(false);
        expect(service.returnDateRangeError).toBe('SHARED.WEEK_FORMAT-WRONG');
    });

    it('should return false because inbound dateFrom is invalid', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
            arrival: 'GDX',
            dateFrom: new Date(2022, 4, 28),
            dateTo: new Date(2022, 4, 29),
        };

        const inbound: Partial<IScheduleRouteDirectionParams> = {
            dateFrom: new Date('invalid'),
        };

        const result = await service.validate({
            outbound: outbound as any,
            inbound: inbound as any,
        });
        expect(result).toBe(false);
        expect(service.returnDateRangeError).toBe('SHARED.WEEK_FORMAT-WRONG');
    });

    it('should return false because inbound dateTo is not provided', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
            arrival: 'GDX',
            dateFrom: new Date(2022, 4, 28),
            dateTo: new Date(2022, 4, 29),
        };

        const inbound: Partial<IScheduleRouteDirectionParams> = {
            dateFrom: new Date(2022, 5, 1),
        };

        const result = await service.validate({
            outbound: outbound as any,
            inbound: inbound as any,
        });
        expect(result).toBe(false);
        expect(service.returnDateRangeError).toBe('SHARED.WEEK_FORMAT-WRONG');
    });

    it('should return false because inbound dateTo is invalid', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
            arrival: 'GDX',
            dateFrom: new Date(2022, 4, 28),
            dateTo: new Date(2022, 4, 29),
        };

        const inbound: Partial<IScheduleRouteDirectionParams> = {
            dateFrom: new Date(2022, 5, 1),
            dateTo: new Date('invalid'),
        };

        const result = await service.validate({
            outbound: outbound as any,
            inbound: inbound as any,
        });
        expect(result).toBe(false);
        expect(service.returnDateRangeError).toBe('SHARED.WEEK_FORMAT-WRONG');
    });

    it('should return true because all params are valid', async () => {
        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
            arrival: 'GDX',
            dateFrom: new Date(2022, 4, 28),
            dateTo: new Date(2022, 4, 29),
        };

        const outboundOnlyResult = await service.validate({
            outbound: outbound as any,
        });
        expect(outboundOnlyResult).toBe(true);

        const inbound: Partial<IScheduleRouteDirectionParams> = {
            dateFrom: new Date(2022, 5, 2),
            dateTo: new Date(2022, 5, 9),
        };
        const result = await service.validate({
            outbound: outbound as any,
            inbound: inbound as any,
        });
        expect(result).toBe(true);
    });

    it('should clear state before validation', async () => {
        let result = await service.validate({
            outbound: {} as any,
        });
        expect(result).toBe(false);
        expect(service.departureError).toBe('SHARED.DEPARTURE-CITY-ERROR');

        const outbound: Partial<IScheduleRouteDirectionParams> = {
            departure: 'MOW',
            arrival: 'GDX',
            dateFrom: new Date(2022, 4, 28),
            dateTo: new Date(2022, 4, 29),
        };

        result = await service.validate({
            outbound: outbound as any,
        });
        expect(result).toBe(true);
        expect(service.departureError).toBe(undefined);
    });
});
