import { CommandHandler } from '@nestjs/cqrs'; import { CreateAdCommand } from '../../commands/create-ad.command'; import { Ad } from '../entities/ad'; import { AdRepository } from '../../adapters/secondaries/ad.repository'; import { InjectMapper } from '@automapper/nestjs'; import { Mapper } from '@automapper/core'; import { CreateAdRequest } from '../dtos/create-ad.request'; import { Inject } from '@nestjs/common'; import { IProvideParams } from '../interfaces/params-provider.interface'; import { ICreateGeorouter } from '../../../geography/domain/interfaces/georouter-creator.interface'; import { IFindTimezone } from '../../../geography/domain/interfaces/timezone-finder.interface'; import { IGeorouter } from '../../../geography/domain/interfaces/georouter.interface'; import { DefaultParams } from '../types/default-params.type'; import { Role } from '../types/role.enum'; import { Geography } from '../entities/geography'; import { IEncodeDirection } from '../../../geography/domain/interfaces/direction-encoder.interface'; import { TimeConverter } from '../entities/time-converter'; import { Coordinate } from '../../../geography/domain/entities/coordinate'; import { DIRECTION_ENCODER, GEOROUTER_CREATOR, PARAMS_PROVIDER, TIMEZONE_FINDER, } from '../../ad.constants'; @CommandHandler(CreateAdCommand) export class CreateAdUseCase { private readonly georouter: IGeorouter; private readonly defaultParams: DefaultParams; private timezone: string; private roles: Role[]; private geography: Geography; private ad: Ad; constructor( @InjectMapper() private readonly mapper: Mapper, private readonly adRepository: AdRepository, @Inject(PARAMS_PROVIDER) private readonly defaultParamsProvider: IProvideParams, @Inject(GEOROUTER_CREATOR) private readonly georouterCreator: ICreateGeorouter, @Inject(TIMEZONE_FINDER) private readonly timezoneFinder: IFindTimezone, @Inject(DIRECTION_ENCODER) private readonly directionEncoder: IEncodeDirection, ) { this.defaultParams = defaultParamsProvider.getParams(); this.georouter = georouterCreator.create( this.defaultParams.GEOROUTER_TYPE, this.defaultParams.GEOROUTER_URL, ); } async execute(command: CreateAdCommand): Promise { try { this.ad = this.mapper.map(command.createAdRequest, CreateAdRequest, Ad); this.setTimezone(command.createAdRequest.addresses); this.setGeography(command.createAdRequest.addresses); this.setRoles(command.createAdRequest); await this.geography.createRoutes(this.roles, this.georouter, { withDistance: false, withPoints: true, withTime: false, }); this.setAdGeography(command); this.setAdSchedule(command); return await this.adRepository.createAd(this.ad); } catch (error) { throw error; } } private setTimezone = (coordinates: Coordinate[]): void => { this.timezone = this.defaultParams.DEFAULT_TIMEZONE; try { const timezones = this.timezoneFinder.timezones( coordinates[0].lon, coordinates[0].lat, ); if (timezones.length > 0) this.timezone = timezones[0]; } catch (e) {} }; private setRoles = (createAdRequest: CreateAdRequest): void => { this.roles = []; if (createAdRequest.driver) this.roles.push(Role.DRIVER); if (createAdRequest.passenger) this.roles.push(Role.PASSENGER); }; private setGeography = (coordinates: Coordinate[]): void => { this.geography = new Geography(coordinates); }; private setAdGeography = (command: CreateAdCommand): void => { this.ad.driverDistance = this.geography.driverRoute?.distance; this.ad.driverDuration = this.geography.driverRoute?.duration; this.ad.passengerDistance = this.geography.passengerRoute?.distance; this.ad.passengerDuration = this.geography.passengerRoute?.duration; this.ad.fwdAzimuth = this.geography.driverRoute ? this.geography.driverRoute.fwdAzimuth : this.geography.passengerRoute.fwdAzimuth; this.ad.backAzimuth = this.geography.driverRoute ? this.geography.driverRoute.backAzimuth : this.geography.passengerRoute.backAzimuth; this.ad.waypoints = this.directionEncoder.encode( command.createAdRequest.addresses, ); this.ad.direction = this.geography.driverRoute ? this.directionEncoder.encode(this.geography.driverRoute.points) : undefined; }; private setAdSchedule = (command: CreateAdCommand): void => { this.ad.monTime = TimeConverter.toUtcDatetime( this.ad.fromDate, command.createAdRequest.monTime, this.timezone, ); this.ad.tueTime = TimeConverter.toUtcDatetime( this.ad.fromDate, command.createAdRequest.tueTime, this.timezone, ); this.ad.wedTime = TimeConverter.toUtcDatetime( this.ad.fromDate, command.createAdRequest.wedTime, this.timezone, ); this.ad.thuTime = TimeConverter.toUtcDatetime( this.ad.fromDate, command.createAdRequest.thuTime, this.timezone, ); this.ad.friTime = TimeConverter.toUtcDatetime( this.ad.fromDate, command.createAdRequest.friTime, this.timezone, ); this.ad.satTime = TimeConverter.toUtcDatetime( this.ad.fromDate, command.createAdRequest.satTime, this.timezone, ); this.ad.sunTime = TimeConverter.toUtcDatetime( this.ad.fromDate, command.createAdRequest.sunTime, this.timezone, ); }; }