import { Inject, Injectable } from '@nestjs/common'; import { CarpoolRouteProviderPort } from '../core/application/ports/carpool-route-provider.port'; import { CarpoolRoute } from '../core/application/types/carpool-route.type'; import { Waypoint } from '../core/application/types/waypoint.type'; import { Role } from '../core/domain/ad.types'; import { GetBasicRouteControllerPort } from '@modules/geography/core/application/ports/get-basic-route-controller.port'; import { AD_GET_BASIC_ROUTE_CONTROLLER } from '../ad.di-tokens'; import { Route } from '@modules/geography/core/domain/route.types'; @Injectable() export class CarpoolRouteProvider implements CarpoolRouteProviderPort { constructor( @Inject(AD_GET_BASIC_ROUTE_CONTROLLER) private readonly getBasicRouteController: GetBasicRouteControllerPort, ) {} getBasic = async ( roles: Role[], waypoints: Waypoint[], ): Promise => { const paths: Path[] = this.getPaths(roles, waypoints); const typeRoutes: TypeRoute[] = await Promise.all( paths.map( async (path: Path) => { type: path.type, route: await this.getBasicRouteController.get({ waypoints, }), }, ), ); return this._toCarpoolRoute(typeRoutes); }; private _toCarpoolRoute = (typeRoutes: TypeRoute[]): CarpoolRoute => { let baseRoute: Route; let driverRoute: Route | undefined; let passengerRoute: Route | undefined; if ( typeRoutes.some( (typeRoute: TypeRoute) => typeRoute.type == PathType.GENERIC, ) ) { driverRoute = passengerRoute = typeRoutes.find( (typeRoute: TypeRoute) => typeRoute.type == PathType.GENERIC, )?.route; } else { driverRoute = typeRoutes.some( (typeRoute: TypeRoute) => typeRoute.type == PathType.DRIVER, ) ? typeRoutes.find( (typeRoute: TypeRoute) => typeRoute.type == PathType.DRIVER, )?.route : undefined; passengerRoute = typeRoutes.some( (typeRoute: TypeRoute) => typeRoute.type == PathType.PASSENGER, ) ? typeRoutes.find( (typeRoute: TypeRoute) => typeRoute.type == PathType.PASSENGER, )?.route : undefined; } if (driverRoute) { baseRoute = driverRoute; } else { baseRoute = passengerRoute as Route; } return { driverDistance: driverRoute?.distance, driverDuration: driverRoute?.duration, passengerDistance: passengerRoute?.distance, passengerDuration: passengerRoute?.duration, fwdAzimuth: baseRoute.fwdAzimuth, backAzimuth: baseRoute.backAzimuth, points: baseRoute.points, }; }; private getPaths = (roles: Role[], waypoints: Waypoint[]): Path[] => { const paths: Path[] = []; if (roles.includes(Role.DRIVER) && roles.includes(Role.PASSENGER)) { if (waypoints.length == 2) { // 2 points => same route for driver and passenger paths.push(this.createGenericPath(waypoints)); } else { paths.push( this.createDriverPath(waypoints), this.createPassengerPath(waypoints), ); } } else if (roles.includes(Role.DRIVER)) { paths.push(this.createDriverPath(waypoints)); } else if (roles.includes(Role.PASSENGER)) { paths.push(this.createPassengerPath(waypoints)); } return paths; }; private createGenericPath = (waypoints: Waypoint[]): Path => this.createPath(waypoints, PathType.GENERIC); private createDriverPath = (waypoints: Waypoint[]): Path => this.createPath(waypoints, PathType.DRIVER); private createPassengerPath = (waypoints: Waypoint[]): Path => this.createPath( [waypoints[0], waypoints[waypoints.length - 1]], PathType.PASSENGER, ); private createPath = (waypoints: Waypoint[], type: PathType): Path => ({ type, waypoints, }); } type Path = { type: PathType; waypoints: Waypoint[]; }; type TypeRoute = { type: PathType; route: Route; }; enum PathType { GENERIC = 'generic', DRIVER = 'driver', PASSENGER = 'passenger', }