/** * Domain Entity: Car * * Represents a racing car/vehicle in the GridPilot platform. * Immutable entity with factory methods and domain validation. */ import type { IEntity } from '@core/shared/domain'; import { RacingDomainValidationError } from '../errors/RacingDomainError'; import { CarName } from './CarName'; import { Manufacturer } from './Manufacturer'; import { CarClass, CarClassType } from './CarClass'; import { CarLicense, CarLicenseType } from './CarLicense'; import { Year } from './Year'; import { Horsepower } from './Horsepower'; import { Weight } from './Weight'; import { GameId } from './GameId'; import { CarId } from './CarId'; import { ImageUrl } from './ImageUrl'; export class Car implements IEntity { readonly id: CarId; readonly name: CarName; readonly shortName: string; readonly manufacturer: Manufacturer; readonly carClass: CarClass; readonly license: CarLicense; readonly year: Year; readonly horsepower: Horsepower | undefined; readonly weight: Weight | undefined; readonly imageUrl: ImageUrl | undefined; readonly gameId: GameId; private constructor(props: { id: CarId; name: CarName; shortName: string; manufacturer: Manufacturer; carClass: CarClass; license: CarLicense; year: Year; horsepower?: Horsepower; weight?: Weight; imageUrl?: ImageUrl; gameId: GameId; }) { this.id = props.id; this.name = props.name; this.shortName = props.shortName; this.manufacturer = props.manufacturer; this.carClass = props.carClass; this.license = props.license; this.year = props.year; this.horsepower = props.horsepower; this.weight = props.weight; this.imageUrl = props.imageUrl; this.gameId = props.gameId; } /** * Factory method to create a new Car entity */ static create(props: { id: string; name: string; shortName?: string; manufacturer: string; carClass?: CarClassType; license?: CarLicenseType; year?: number; horsepower?: number; weight?: number; imageUrl?: string; gameId: string; }): Car { this.validate(props); return new Car({ id: CarId.create(props.id), name: CarName.create(props.name), shortName: props.shortName ?? props.name.slice(0, 10), manufacturer: Manufacturer.create(props.manufacturer), carClass: CarClass.create(props.carClass ?? 'gt'), license: CarLicense.create(props.license ?? 'D'), year: Year.create(props.year ?? new Date().getFullYear()), ...(props.horsepower !== undefined ? { horsepower: Horsepower.create(props.horsepower) } : {}), ...(props.weight !== undefined ? { weight: Weight.create(props.weight) } : {}), ...(props.imageUrl !== undefined ? { imageUrl: ImageUrl.create(props.imageUrl) } : {}), gameId: GameId.create(props.gameId), }); } /** * Domain validation logic */ private static validate(props: { id: string; name: string; manufacturer: string; gameId: string; }): void { if (!props.id || props.id.trim().length === 0) { throw new RacingDomainValidationError('Car ID is required'); } if (!props.name || props.name.trim().length === 0) { throw new RacingDomainValidationError('Car name is required'); } if (!props.manufacturer || props.manufacturer.trim().length === 0) { throw new RacingDomainValidationError('Car manufacturer is required'); } if (!props.gameId || props.gameId.trim().length === 0) { throw new RacingDomainValidationError('Game ID is required'); } } }