/** * @ai-summary Platform API controller * @ai-context Request handlers for vehicle data and VIN decoding endpoints */ import { FastifyRequest, FastifyReply } from 'fastify'; import { Pool } from 'pg'; import { VehicleDataService } from '../domain/vehicle-data.service'; import { VINDecodeService } from '../domain/vin-decode.service'; import { PlatformCacheService } from '../domain/platform-cache.service'; import { cacheService } from '../../../core/config/redis'; import { MakesQuery, ModelsQuery, TrimsQuery, EnginesQuery, VINDecodeRequest } from '../models/requests'; import { logger } from '../../../core/logging/logger'; export class PlatformController { private vehicleDataService: VehicleDataService; private vinDecodeService: VINDecodeService; private pool: Pool; constructor(pool: Pool) { this.pool = pool; const platformCache = new PlatformCacheService(cacheService); this.vehicleDataService = new VehicleDataService(platformCache); this.vinDecodeService = new VINDecodeService(platformCache); } /** * GET /api/platform/years */ async getYears(_request: FastifyRequest, reply: FastifyReply): Promise { try { const years = await this.vehicleDataService.getYears(this.pool); reply.code(200).send(years); } catch (error) { logger.error('Controller error: getYears', { error }); reply.code(500).send({ error: 'Failed to retrieve years' }); } } /** * GET /api/platform/makes?year={year} */ async getMakes(request: FastifyRequest<{ Querystring: MakesQuery }>, reply: FastifyReply): Promise { try { const { year } = request.query; const makes = await this.vehicleDataService.getMakes(this.pool, year); reply.code(200).send({ makes }); } catch (error) { logger.error('Controller error: getMakes', { error, query: request.query }); reply.code(500).send({ error: 'Failed to retrieve makes' }); } } /** * GET /api/platform/models?year={year}&make_id={id} */ async getModels(request: FastifyRequest<{ Querystring: ModelsQuery }>, reply: FastifyReply): Promise { try { const { year, make_id } = request.query; const models = await this.vehicleDataService.getModels(this.pool, year, make_id); reply.code(200).send({ models }); } catch (error) { logger.error('Controller error: getModels', { error, query: request.query }); reply.code(500).send({ error: 'Failed to retrieve models' }); } } /** * GET /api/platform/trims?year={year}&model_id={id} */ async getTrims(request: FastifyRequest<{ Querystring: TrimsQuery }>, reply: FastifyReply): Promise { try { const { year, model_id } = request.query; const trims = await this.vehicleDataService.getTrims(this.pool, year, model_id); reply.code(200).send({ trims }); } catch (error) { logger.error('Controller error: getTrims', { error, query: request.query }); reply.code(500).send({ error: 'Failed to retrieve trims' }); } } /** * GET /api/platform/engines?year={year}&model_id={id}&trim_id={id} */ async getEngines(request: FastifyRequest<{ Querystring: EnginesQuery }>, reply: FastifyReply): Promise { try { const { year, model_id, trim_id } = request.query; const engines = await this.vehicleDataService.getEngines(this.pool, year, model_id, trim_id); reply.code(200).send({ engines }); } catch (error) { logger.error('Controller error: getEngines', { error, query: request.query }); reply.code(500).send({ error: 'Failed to retrieve engines' }); } } /** * GET /api/platform/vehicle?vin={vin} */ async decodeVIN(request: FastifyRequest<{ Querystring: VINDecodeRequest }>, reply: FastifyReply): Promise { try { const { vin } = request.query; const result = await this.vinDecodeService.decodeVIN(this.pool, vin); if (!result.success) { if (result.error && result.error.includes('Invalid VIN')) { reply.code(400).send(result); } else if (result.error && result.error.includes('unavailable')) { reply.code(503).send(result); } else { reply.code(404).send(result); } return; } reply.code(200).send(result); } catch (error) { logger.error('Controller error: decodeVIN', { error, query: request.query }); reply.code(500).send({ vin: request.query.vin, result: null, success: false, error: 'Internal server error during VIN decoding' }); } } }