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 { OnlineBoardRouteFilterValidationService } from '@online-board/components/filter/components/route-filter/services/online-board-route-filter-validation.service';
import { IOnlineBoardRoutePageUrlParams } from '@online-board/services/url';
import { StationCodeValidationService } from '@shared/services/validators/station-code.service';

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

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

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

    it('should return false because departure and arrival are not provided', async () => {
        const params: Partial<IOnlineBoardRoutePageUrlParams> = {};
        const result = await service.validate(params);

        expect(result).toBe(false);
        expect(service.departureError).toBe('SHARED.DEPARTURE-CITY-ERROR');
        expect(service.arrivalError).toBe('SHARED.ARRIVAL-CITY-ERROR');
    });

    it('should return false because departure is not valid', async () => {
        const params: Partial<IOnlineBoardRoutePageUrlParams> = {
            departure: 'AAA',
        };
        const result = await service.validate(params);

        expect(result).toBe(false);
        expect(service.departureError).toBe('SHARED.DEPARTURE-CITY-ERROR');
        expect(service.arrivalError).toBe(null);
    });

    it('should return false because arrival is not valid', async () => {
        const params: Partial<IOnlineBoardRoutePageUrlParams> = {
            arrival: 'AAA',
        };
        const result = await service.validate(params);

        expect(result).toBe(false);
        expect(service.departureError).toBe(null);
        expect(service.arrivalError).toBe('SHARED.ARRIVAL-CITY-ERROR');
    });

    it('should return false because arrival equals to departure', async () => {
        const params: Partial<IOnlineBoardRoutePageUrlParams> = {
            arrival: 'MOW',
            departure: 'MOW',
        };
        const result = await service.validate(params);

        expect(result).toBe(false);
        expect(service.departureError).toBe(
            'SHARED.ARRIVAL-EQUALS-DEPARTURE-ERROR',
        );
        expect(service.arrivalError).toBe(null);
    });

    it('should return false because date is not provided', async () => {
        const params: Partial<IOnlineBoardRoutePageUrlParams> = {
            arrival: 'MOW',
        };
        const result = await service.validate(params);

        expect(result).toBe(false);
        expect(service.departureError).toBe(null);
        expect(service.arrivalError).toBe(null);
        expect(service.dateError).toBe('SHARED.DATE_FORMAT-WRONG');
    });

    it('should return false because date is invalid', async () => {
        const params: Partial<IOnlineBoardRoutePageUrlParams> = {
            arrival: 'MOW',
            date: new Date('invalid'),
        };
        const result = await service.validate(params);

        expect(result).toBe(false);
        expect(service.departureError).toBe(null);
        expect(service.arrivalError).toBe(null);
        expect(service.dateError).toBe('SHARED.DATE_FORMAT-WRONG');
    });

    it('should return true because all params are valid', async () => {
        function assertTrue(result: boolean) {
            expect(result).toBe(true);
            expect(service.departureError).toBe(null);
            expect(service.arrivalError).toBe(null);
            expect(service.dateError).toBe(null);
        }
        const date = new Date(2022, 4, 28);

        const arrivalParams: Partial<IOnlineBoardRoutePageUrlParams> = {
            arrival: 'MOW',
            date,
        };
        const arrivalResult = await service.validate(arrivalParams);
        assertTrue(arrivalResult);

        const departureParams: Partial<IOnlineBoardRoutePageUrlParams> = {
            departure: 'MOW',
            date,
        };
        const departureResult = await service.validate(departureParams);
        assertTrue(departureResult);

        const routeParams: Partial<IOnlineBoardRoutePageUrlParams> = {
            departure: 'MOW',
            arrival: 'GDX',
            date,
        };
        const routeResult = await service.validate(routeParams);
        assertTrue(routeResult);
    });

    it('should clear errors before validation', async () => {
        const invalidParams: Partial<IOnlineBoardRoutePageUrlParams> = {};
        const invalidResult = await service.validate(invalidParams);

        expect(invalidResult).toBe(false);
        expect(service.departureError).toBe('SHARED.DEPARTURE-CITY-ERROR');
        expect(service.arrivalError).toBe('SHARED.ARRIVAL-CITY-ERROR');

        const validParams: Partial<IOnlineBoardRoutePageUrlParams> = {
            arrival: 'MOW',
            date: new Date(2022, 4, 28),
        };
        const validResult = await service.validate(validParams);

        expect(validResult).toBe(true);
        expect(service.departureError).toBe(null);
        expect(service.arrivalError).toBe(null);
        expect(service.dateError).toBe(null);
    });
});
