import { Inject, Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
import { ScheduleDateValidationService } from '@schedule/services/date-validation.service';
import { ScheduleRequestParserService } from '@schedule/services/request/request-parser.service';
import { ScheduleRouteParamsValidationService } from '@schedule/services/route-params-validation.service';
import { FLIGHTS_INFO_PARAM } from '@schedule/services/url/flights-info-param';
import { IScheduleDetailsParams } from '@schedule/services/url/types';
import { ScheduleUrlParserService } from '@schedule/services/url/url-parser.service';
import { RootNavigationService } from '@shared/services/navigation.service';
import { CanActivateRedirrect } from './can-activate-redirrect-to-not-found';

@Injectable()
export class CanActivateScheduleDetails implements CanActivate {
    constructor(
        private dateValidator: ScheduleDateValidationService,
        private rootNavigationService: RootNavigationService,
        private urlService: ScheduleUrlParserService,
        private requestService: ScheduleRequestParserService,
        private routeParamsValidator: ScheduleRouteParamsValidationService,
        private canRedirrect: CanActivateRedirrect,
        private router: Router,
        @Inject(FLIGHTS_INFO_PARAM) private flightsInfoParamName,
    ) { }

    async canActivate(route: ActivatedRouteSnapshot) {
        const flightsIds = this.urlService.parseFlightDetailsParams(
            route.params[this.flightsInfoParamName],
            null, // do not need departure and arrival here
            null,
        );

        // can open details WO request param -> need ti validate here
        for (let i = 0; i < flightsIds.flights.length; i++) {
            if (!this.canRedirrect.validateStation(flightsIds.flights[i].arrival)
                || !this.canRedirrect.validateStation(flightsIds.flights[i].departure)
                || !this.canRedirrect.validateFlightNumber(flightsIds.flights[i].flightNumber)) {
                return this.rootNavigationService.toNotFound();
            }
        }

        const areDatesValid = await this.areDatesValid(flightsIds);

        if (!areDatesValid) {
            return this.router.navigateByUrl(this.urlService.base);
        }

        const isRequestValid = await this.isRequestValid(
            route.queryParams.request,
        );

        if (!isRequestValid) {
            const url = route.url.map((item) => item.path).join('/');

            return this.router.navigateByUrl(`${this.urlService.base}/${url}`);
        }

        return true;
    }

    private async areDatesValid(flightsInfo: IScheduleDetailsParams) {
        try {
            const promises = flightsInfo.flights.map(({ date }) => {
                return this.dateValidator.isDateValid(date);
            });
            const results = await Promise.all(promises);

            return results.every(Boolean);
        } catch {
            return false;
        }
    }

    private async isRequestValid(request?: string) {
        if (!request) {
            return true;
        }

        const { outbound, inbound } =
            this.requestService.parseRouteRequest(request);

        if (!this.canRedirrect.validateTimeRange(outbound.timeFrom, outbound.timeTo)
            || !this.canRedirrect.validateStation(outbound.arrival)
            || !this.canRedirrect.validateStation(outbound.departure)
            || !outbound.dateFrom
            || !outbound.dateTo) {
            this.rootNavigationService.toNotFound();
        }

        if (inbound) {
            if (!this.canRedirrect.validateTimeRange(inbound.timeFrom, inbound.timeTo)
                || !this.canRedirrect.validateStation(inbound.arrival)
                || !this.canRedirrect.validateStation(inbound.departure)
                || !inbound.dateFrom
                || !inbound.dateTo) {
                this.rootNavigationService.toNotFound();
            }
        }

        const routeValidationResult =
            await this.routeParamsValidator.validateRoute(outbound, inbound);

        return routeValidationResult.isValid;
    }
}
