/**
 * @ai-summary Business logic for vehicles feature
 * @ai-context Handles VIN decoding, caching, and business rules
 */

import { Pool } from 'pg';
import { VehiclesRepository } from '../data/vehicles.repository';
import {
  Vehicle,
  CreateVehicleRequest,
  UpdateVehicleRequest,
  VehicleResponse,
  VehicleImageMeta,
  TCOResponse,
  CostInterval,
  PAYMENTS_PER_YEAR
} from './vehicles.types';
import { logger } from '../../../core/logging/logger';
import { cacheService } from '../../../core/config/redis';
import { getStorageService } from '../../../core/storage/storage.service';
import * as fs from 'fs/promises';
import * as path from 'path';
import { isValidVIN, isValidPreModernVIN } from '../../../shared-minimal/utils/validators';
import { normalizeMakeName, normalizeModelName } from './name-normalizer';
import { getVehicleDataService, getPool } from '../../platform';
import { auditLogService } from '../../audit-log';
import { NHTSAClient, NHTSADecodeResponse, DecodedVehicleData, MatchedField } from '../external/nhtsa';
import { canAddVehicle, getVehicleLimitConfig } from '../../../core/config/feature-tiers';
import { UserProfileRepository } from '../../user-profile/data/user-profile.repository';
import { SubscriptionTier } from '../../user-profile/domain/user-profile.types';
import { OwnershipCostsService } from '../../ownership-costs';
import { FuelLogsService } from '../../fuel-logs/domain/fuel-logs.service';
import { FuelLogsRepository } from '../../fuel-logs/data/fuel-logs.repository';
import { MaintenanceService } from '../../maintenance/domain/maintenance.service';
import { UserSettingsService } from '../../fuel-logs/external/user-settings.service';

export class VehicleLimitExceededError extends Error {
  constructor(
    public tier: SubscriptionTier,
    public currentCount: number,
    public limit: number,
    public upgradePrompt: string
  ) {
    super('Vehicle limit exceeded');
    this.name = 'VehicleLimitExceededError';
  }
}

export class VehiclesService {
  private readonly cachePrefix = 'vehicles';
  private readonly listCacheTTL = 300; // 5 minutes
  private userProfileRepository: UserProfileRepository;

  constructor(
    private repository: VehiclesRepository,
    private pool: Pool
  ) {
    // VIN decode service is now provided by platform feature
    this.userProfileRepository = new UserProfileRepository(pool);
  }
  
  async createVehicle(data: CreateVehicleRequest, userId: string): Promise<VehicleResponse> {
    logger.info('Creating vehicle', { userId, vin: data.vin, licensePlate: data.licensePlate });

    // Pre-1981 vehicles have relaxed VIN format requirements
    const isPreModern = data.year && data.year < 1981;

    if (data.vin) {
      // Validate VIN format based on vehicle year
      if (isPreModern) {
        if (!isValidPreModernVIN(data.vin)) {
          throw new Error('Invalid VIN format for pre-1981 vehicle');
        }
      } else if (!isValidVIN(data.vin)) {
        throw new Error('Invalid VIN format');
      }
      // Duplicate check only when VIN is present
      const existing = await this.repository.findByUserAndVIN(userId, data.vin);
      if (existing) {
        throw new Error('Vehicle with this VIN already exists');
      }
    }

    // Get user's tier for limit enforcement
    const userProfile = await this.userProfileRepository.getByAuth0Sub(userId);
    if (!userProfile) {
      throw new Error('User profile not found');
    }
    const userTier = userProfile.subscriptionTier;

    // Tier limit enforcement with transaction + FOR UPDATE locking to prevent race condition
    const client = await this.pool.connect();
    try {
      await client.query('BEGIN');

      // Lock user's vehicle rows and get count
      // Note: Cannot use COUNT(*) with FOR UPDATE, so we select IDs and count in app
      const lockResult = await client.query(
        'SELECT id FROM vehicles WHERE user_id = $1 AND is_active = true FOR UPDATE',
        [userId]
      );
      const currentCount = lockResult.rows.length;

      // Check if user can add another vehicle
      if (!canAddVehicle(userTier, currentCount)) {
        await client.query('ROLLBACK');
        const limitConfig = getVehicleLimitConfig(userTier);
        throw new VehicleLimitExceededError(
          userTier,
          currentCount,
          limitConfig.limit!,
          limitConfig.upgradePrompt
        );
      }

      // Create vehicle with user-provided data (within transaction)
      const query = `
        INSERT INTO vehicles (
          user_id, vin, make, model, year,
          engine, transmission, trim_level, drive_type, fuel_type,
          nickname, color, license_plate, odometer_reading
        )
        VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
        RETURNING *
      `;

      const values = [
        userId,
        (data.vin && data.vin.trim().length > 0) ? data.vin.trim() : null,
        data.make ? normalizeMakeName(data.make) : null,
        data.model ? normalizeModelName(data.model) : null,
        data.year,
        data.engine,
        data.transmission,
        data.trimLevel,
        data.driveType,
        data.fuelType,
        data.nickname,
        data.color,
        data.licensePlate,
        data.odometerReading || 0
      ];

      const result = await client.query(query, values);
      await client.query('COMMIT');

      const vehicle = this.mapVehicleRow(result.rows[0]);

      // Invalidate user's vehicle list cache
      await this.invalidateUserCache(userId);

      // Log vehicle creation to unified audit log
      const vehicleDesc = [vehicle.year, vehicle.make, vehicle.model].filter(Boolean).join(' ');
      await auditLogService.info(
        'vehicle',
        userId,
        `Vehicle created: ${vehicleDesc || vehicle.id}`,
        'vehicle',
        vehicle.id,
        { vin: vehicle.vin, make: vehicle.make, model: vehicle.model, year: vehicle.year }
      ).catch(err => logger.error('Failed to log vehicle create audit event', { error: err }));

      return this.toResponse(vehicle);
    } catch (error) {
      await client.query('ROLLBACK');
      throw error;
    } finally {
      client.release();
    }
  }

  /**
   * Map database row to Vehicle domain object
   */
  private mapVehicleRow(row: any): Vehicle {
    return {
      id: row.id,
      userId: row.user_id,
      vin: row.vin,
      make: row.make,
      model: row.model,
      year: row.year,
      engine: row.engine,
      transmission: row.transmission,
      trimLevel: row.trim_level,
      driveType: row.drive_type,
      fuelType: row.fuel_type,
      nickname: row.nickname,
      color: row.color,
      licensePlate: row.license_plate,
      odometerReading: row.odometer_reading,
      isActive: row.is_active,
      deletedAt: row.deleted_at,
      createdAt: row.created_at,
      updatedAt: row.updated_at,
      imageStorageBucket: row.image_storage_bucket,
      imageStorageKey: row.image_storage_key,
      imageFileName: row.image_file_name,
      imageContentType: row.image_content_type,
      imageFileSize: row.image_file_size,
    };
  }

  async getUserVehicles(userId: string): Promise<VehicleResponse[]> {
    const cacheKey = `${this.cachePrefix}:user:${userId}`;

    // Check cache
    const cached = await cacheService.get<VehicleResponse[]>(cacheKey);
    if (cached) {
      logger.debug('Vehicle list cache hit', { userId });
      return cached;
    }

    // Get from database
    const vehicles = await this.repository.findByUserId(userId);
    const response = vehicles.map((v: Vehicle) => this.toResponse(v));

    // Cache result
    await cacheService.set(cacheKey, response, this.listCacheTTL);

    return response;
  }

  /**
   * Get user vehicles with tier-gated status
   * Returns vehicles with tierStatus: 'active' | 'locked'
   */
  async getUserVehiclesWithTierStatus(userId: string): Promise<Array<VehicleResponse & { tierStatus: 'active' | 'locked' }>> {
    // Get user's subscription tier
    const userProfile = await this.userProfileRepository.getByAuth0Sub(userId);
    if (!userProfile) {
      throw new Error('User profile not found');
    }
    const userTier = userProfile.subscriptionTier;

    // Get all vehicles
    const vehicles = await this.repository.findByUserId(userId);

    // Define tier limits
    const tierLimits: Record<SubscriptionTier, number | null> = {
      free: 2,
      pro: 5,
      enterprise: null, // unlimited
    };

    const tierLimit = tierLimits[userTier];

    // If tier has unlimited vehicles, all are active
    if (tierLimit === null) {
      return vehicles.map((v: Vehicle) => ({
        ...this.toResponse(v),
        tierStatus: 'active' as const,
      }));
    }

    // If vehicle count is within tier limit, all are active
    if (vehicles.length <= tierLimit) {
      return vehicles.map((v: Vehicle) => ({
        ...this.toResponse(v),
        tierStatus: 'active' as const,
      }));
    }

    // Vehicle count exceeds tier limit - check for tier_vehicle_selections
    // Get vehicle selections from subscriptions repository
    const { SubscriptionsRepository } = await import('../../subscriptions/data/subscriptions.repository');
    const subscriptionsRepo = new SubscriptionsRepository(this.pool);
    const selections = await subscriptionsRepo.findVehicleSelectionsByUserId(userId);
    const selectedVehicleIds = new Set(selections.map(s => s.vehicleId));

    // If no selections exist, return all as active (selections only exist after downgrade)
    if (selections.length === 0) {
      return vehicles.map((v: Vehicle) => ({
        ...this.toResponse(v),
        tierStatus: 'active' as const,
      }));
    }

    // Mark vehicles as active or locked based on selections
    return vehicles.map((v: Vehicle) => ({
      ...this.toResponse(v),
      tierStatus: selectedVehicleIds.has(v.id) ? ('active' as const) : ('locked' as const),
    }));
  }
  
  async getVehicle(id: string, userId: string): Promise<VehicleResponse> {
    const vehicle = await this.repository.findById(id);
    
    if (!vehicle) {
      throw new Error('Vehicle not found');
    }
    
    if (vehicle.userId !== userId) {
      throw new Error('Unauthorized');
    }
    
    return this.toResponse(vehicle);
  }
  
  async updateVehicle(
    id: string,
    data: UpdateVehicleRequest,
    userId: string
  ): Promise<VehicleResponse> {
    // Verify ownership
    const existing = await this.repository.findById(id);
    if (!existing) {
      throw new Error('Vehicle not found');
    }
    if (existing.userId !== userId) {
      throw new Error('Unauthorized');
    }

    // Determine the effective year for validation (use new year if provided, else existing)
    const effectiveYear = data.year !== undefined ? data.year : existing.year;
    const isPreModern = effectiveYear && effectiveYear < 1981;

    // Validate VIN if provided
    if (data.vin !== undefined && data.vin.trim().length > 0) {
      const trimmedVin = data.vin.trim();
      // Validate VIN format based on vehicle year
      if (isPreModern) {
        if (!isValidPreModernVIN(trimmedVin)) {
          throw new Error('Invalid VIN format for pre-1981 vehicle');
        }
      } else if (!isValidVIN(trimmedVin)) {
        throw new Error('Invalid VIN format');
      }
      // Check for duplicate VIN (only if VIN is changing)
      if (trimmedVin !== existing.vin) {
        const duplicate = await this.repository.findByUserAndVIN(userId, trimmedVin);
        if (duplicate && duplicate.id !== id) {
          throw new Error('Vehicle with this VIN already exists');
        }
      }
    }

    // Normalize any provided name fields
    const normalized: UpdateVehicleRequest = { ...data } as any;
    if (data.make !== undefined) {
      (normalized as any).make = normalizeMakeName(data.make);
    }
    if (data.model !== undefined) {
      (normalized as any).model = normalizeModelName(data.model);
    }

    // Update vehicle
    const updated = await this.repository.update(id, normalized);
    if (!updated) {
      throw new Error('Update failed');
    }

    // Invalidate cache
    await this.invalidateUserCache(userId);

    // Log vehicle update to unified audit log
    const vehicleDesc = [updated.year, updated.make, updated.model].filter(Boolean).join(' ');
    await auditLogService.info(
      'vehicle',
      userId,
      `Vehicle updated: ${vehicleDesc || id}`,
      'vehicle',
      id,
      { updatedFields: Object.keys(data) }
    ).catch(err => logger.error('Failed to log vehicle update audit event', { error: err }));

    return this.toResponse(updated);
  }

  async deleteVehicle(id: string, userId: string): Promise<void> {
    // Verify ownership
    const existing = await this.repository.findById(id);
    if (!existing) {
      throw new Error('Vehicle not found');
    }
    if (existing.userId !== userId) {
      throw new Error('Unauthorized');
    }

    logger.info('Deleting vehicle', {
      vehicleId: id,
      userId,
      hasImageKey: !!existing.imageStorageKey,
      hasImageBucket: !!existing.imageStorageBucket,
      imageStorageKey: existing.imageStorageKey,
      imageStorageBucket: existing.imageStorageBucket
    });

    // Delete associated image from storage if present
    if (existing.imageStorageKey && existing.imageStorageBucket) {
      try {
        const storage = getStorageService();
        logger.info('Attempting to delete vehicle image', {
          vehicleId: id,
          bucket: existing.imageStorageBucket,
          key: existing.imageStorageKey
        });
        await storage.deleteObject(existing.imageStorageBucket, existing.imageStorageKey);
        logger.info('Successfully deleted vehicle image on vehicle deletion', {
          vehicleId: id,
          bucket: existing.imageStorageBucket,
          key: existing.imageStorageKey
        });

        // Clean up empty vehicle directory
        // Key format: vehicle-images/{userId}/{vehicleId}/{filename}
        const basePath = '/app/data/documents';
        const vehicleDir = path.join(basePath, path.dirname(existing.imageStorageKey));
        try {
          await fs.rmdir(vehicleDir);
          logger.info('Removed empty vehicle image directory', { vehicleId: id, directory: vehicleDir });
        } catch (dirError) {
          // Directory might not be empty or might not exist, ignore
          logger.debug('Could not remove vehicle image directory', {
            vehicleId: id,
            directory: vehicleDir,
            error: dirError instanceof Error ? dirError.message : String(dirError)
          });
        }
      } catch (error) {
        // Log warning but don't block vehicle deletion on storage failure
        logger.warn('Failed to delete vehicle image on vehicle deletion', {
          vehicleId: id,
          bucket: existing.imageStorageBucket,
          key: existing.imageStorageKey,
          error: error instanceof Error ? error.message : String(error)
        });
      }
    } else {
      logger.info('No image to delete for vehicle', { vehicleId: id });
    }

    // Soft delete
    await this.repository.softDelete(id);

    // Invalidate cache
    await this.invalidateUserCache(userId);

    // Log vehicle deletion to unified audit log
    const vehicleDesc = [existing.year, existing.make, existing.model].filter(Boolean).join(' ');
    await auditLogService.info(
      'vehicle',
      userId,
      `Vehicle deleted: ${vehicleDesc || id}`,
      'vehicle',
      id,
      { vin: existing.vin, make: existing.make, model: existing.model, year: existing.year }
    ).catch(err => logger.error('Failed to log vehicle delete audit event', { error: err }));
  }

  async getTCO(id: string, userId: string): Promise<TCOResponse> {
    // Get vehicle and verify ownership
    const vehicle = await this.repository.findById(id);
    if (!vehicle) {
      const err: any = new Error('Vehicle not found');
      err.statusCode = 404;
      throw err;
    }
    if (vehicle.userId !== userId) {
      const err: any = new Error('Unauthorized');
      err.statusCode = 403;
      throw err;
    }

    // Get user preferences for units
    const userSettings = await UserSettingsService.getUserSettings(userId);
    const distanceUnit = userSettings.unitSystem === 'metric' ? 'km' : 'mi';
    const currencyCode = userSettings.currencyCode || 'USD';

    // Get fuel costs from fuel-logs service
    const fuelLogsRepository = new FuelLogsRepository(this.pool);
    const fuelLogsService = new FuelLogsService(fuelLogsRepository);
    let fuelCosts = 0;
    try {
      const fuelStats = await fuelLogsService.getVehicleStats(id, userId);
      fuelCosts = fuelStats.totalCost || 0;
    } catch {
      // Vehicle may have no fuel logs
      fuelCosts = 0;
    }

    // Get maintenance costs from maintenance service
    const maintenanceService = new MaintenanceService();
    let maintenanceCosts = 0;
    try {
      const maintenanceStats = await maintenanceService.getVehicleMaintenanceCosts(id, userId);
      maintenanceCosts = maintenanceStats.totalCost || 0;
    } catch {
      // Vehicle may have no maintenance records
      maintenanceCosts = 0;
    }

    // Get fixed costs from vehicle record
    const purchasePrice = vehicle.purchasePrice || 0;

    // Get recurring ownership costs from ownership-costs service
    const ownershipCostsService = new OwnershipCostsService(this.pool);
    let insuranceCosts = 0;
    let registrationCosts = 0;
    let taxCosts = 0;
    let otherCosts = 0;
    try {
      const ownershipStats = await ownershipCostsService.getVehicleCostStats(id, userId);
      insuranceCosts = ownershipStats.insuranceCosts || 0;
      registrationCosts = ownershipStats.registrationCosts || 0;
      taxCosts = ownershipStats.taxCosts || 0;
      otherCosts = ownershipStats.otherCosts || 0;
    } catch {
      // Vehicle may have no ownership cost records
      // Fall back to legacy vehicle fields if they exist
      insuranceCosts = this.normalizeRecurringCost(
        vehicle.insuranceCost,
        vehicle.insuranceInterval,
        vehicle.purchaseDate
      );
      registrationCosts = this.normalizeRecurringCost(
        vehicle.registrationCost,
        vehicle.registrationInterval,
        vehicle.purchaseDate
      );
    }

    // Calculate lifetime total (includes all ownership costs: insurance, registration, tax, other)
    const lifetimeTotal = purchasePrice + insuranceCosts + registrationCosts + taxCosts + otherCosts + fuelCosts + maintenanceCosts;

    // Calculate cost per distance
    const odometerReading = vehicle.odometerReading || 0;
    const costPerDistance = odometerReading > 0 ? lifetimeTotal / odometerReading : 0;

    return {
      vehicleId: id,
      purchasePrice,
      insuranceCosts,
      registrationCosts,
      taxCosts,
      otherCosts,
      fuelCosts,
      maintenanceCosts,
      lifetimeTotal,
      costPerDistance,
      distanceUnit,
      currencyCode
    };
  }

  private normalizeRecurringCost(
    cost: number | null | undefined,
    interval: CostInterval | null | undefined,
    purchaseDate: string | null | undefined
  ): number {
    if (!cost || !interval || !purchaseDate) return 0;

    const monthsOwned = Math.max(1, this.calculateMonthsOwned(purchaseDate));
    const paymentsPerYear = PAYMENTS_PER_YEAR[interval];
    if (!paymentsPerYear) {
      throw new Error(`Invalid cost interval: ${interval}`);
    }
    const totalPayments = (monthsOwned / 12) * paymentsPerYear;
    return cost * totalPayments;
  }

  private calculateMonthsOwned(purchaseDate: string): number {
    const purchase = new Date(purchaseDate);
    const now = new Date();
    // Guard against future dates - treat as 0 months owned
    if (purchase > now) {
      return 0;
    }
    const yearDiff = now.getFullYear() - purchase.getFullYear();
    const monthDiff = now.getMonth() - purchase.getMonth();
    return yearDiff * 12 + monthDiff;
  }

  async getVehicleRaw(id: string, userId: string): Promise<Vehicle | null> {
    const vehicle = await this.repository.findById(id);
    if (!vehicle || vehicle.userId !== userId) {
      return null;
    }
    return vehicle;
  }

  async updateVehicleImage(id: string, userId: string, meta: VehicleImageMeta | null): Promise<VehicleResponse | null> {
    const updated = await this.repository.updateImageMeta(id, userId, meta);
    if (!updated) {
      return null;
    }
    await this.invalidateUserCache(userId);
    return this.toResponse(updated);
  }

  private async invalidateUserCache(userId: string): Promise<void> {
    const cacheKey = `${this.cachePrefix}:user:${userId}`;
    await cacheService.del(cacheKey);
  }
  
  async getDropdownMakes(year: number): Promise<string[]> {
    const vehicleDataService = getVehicleDataService();
    const pool = getPool();

    logger.info('Fetching dropdown makes via platform module', { year });
    return vehicleDataService.getMakes(pool, year);
  }

  async getDropdownModels(year: number, make: string): Promise<string[]> {
    const vehicleDataService = getVehicleDataService();
    const pool = getPool();

    logger.info('Fetching dropdown models via platform module', { year, make });
    return vehicleDataService.getModels(pool, year, make);
  }

  async getDropdownTransmissions(year: number, make: string, model: string, trim: string): Promise<string[]> {
    const vehicleDataService = getVehicleDataService();
    const pool = getPool();

    logger.info('Fetching dropdown transmissions via platform module', { year, make, model, trim });
    return vehicleDataService.getTransmissionsForTrim(pool, year, make, model, trim);
  }

  async getDropdownEngines(year: number, make: string, model: string, trim: string): Promise<string[]> {
    const vehicleDataService = getVehicleDataService();
    const pool = getPool();

    logger.info('Fetching dropdown engines via platform module', { year, make, model, trim });
    return vehicleDataService.getEngines(pool, year, make, model, trim);
  }

  async getDropdownTrims(year: number, make: string, model: string): Promise<string[]> {
    const vehicleDataService = getVehicleDataService();
    const pool = getPool();

    logger.info('Fetching dropdown trims via platform module', { year, make, model });
    return vehicleDataService.getTrims(pool, year, make, model);
  }

  async getDropdownOptions(
    year: number,
    make: string,
    model: string,
    trim: string,
    engine?: string,
    transmission?: string
  ): Promise<{ engines: string[]; transmissions: string[] }> {
    const vehicleDataService = getVehicleDataService();
    const pool = getPool();

    logger.info('Fetching dropdown options via platform module', { year, make, model, trim, engine, transmission });
    return vehicleDataService.getOptions(pool, year, make, model, trim, engine, transmission);
  }

  async getDropdownYears(): Promise<number[]> {
    const vehicleDataService = getVehicleDataService();
    const pool = getPool();

    logger.info('Fetching dropdown years via platform module');
    return vehicleDataService.getYears(pool);
  }

  /**
   * Map NHTSA decode response to internal decoded vehicle data format
   * with dropdown matching and confidence levels
   */
  async mapNHTSAResponse(response: NHTSADecodeResponse): Promise<DecodedVehicleData> {
    const vehicleDataService = getVehicleDataService();
    const pool = getPool();

    // Extract raw values from NHTSA response
    const nhtsaYear = NHTSAClient.extractYear(response);
    const nhtsaMake = NHTSAClient.extractValue(response, 'Make');
    const nhtsaModel = NHTSAClient.extractValue(response, 'Model');
    const nhtsaTrim = NHTSAClient.extractValue(response, 'Trim');
    const nhtsaBodyType = NHTSAClient.extractValue(response, 'Body Class');
    const nhtsaDriveType = NHTSAClient.extractValue(response, 'Drive Type');
    const nhtsaFuelType = NHTSAClient.extractValue(response, 'Fuel Type - Primary');
    const nhtsaEngine = NHTSAClient.extractEngine(response);
    const nhtsaTransmission = NHTSAClient.extractValue(response, 'Transmission Style');

    // Year is always high confidence if present (exact numeric match)
    const year: MatchedField<number> = {
      value: nhtsaYear,
      nhtsaValue: nhtsaYear?.toString() || null,
      confidence: nhtsaYear ? 'high' : 'none'
    };

    // Match make against dropdown options
    let make: MatchedField<string> = { value: null, nhtsaValue: nhtsaMake, confidence: 'none' };
    if (nhtsaYear && nhtsaMake) {
      const makes = await vehicleDataService.getMakes(pool, nhtsaYear);
      make = this.matchField(nhtsaMake, makes);
    }

    // Match model against dropdown options
    let model: MatchedField<string> = { value: null, nhtsaValue: nhtsaModel, confidence: 'none' };
    if (nhtsaYear && make.value && nhtsaModel) {
      const models = await vehicleDataService.getModels(pool, nhtsaYear, make.value);
      model = this.matchField(nhtsaModel, models);
    }

    // Match trim against dropdown options
    let trimLevel: MatchedField<string> = { value: null, nhtsaValue: nhtsaTrim, confidence: 'none' };
    if (nhtsaYear && make.value && model.value && nhtsaTrim) {
      const trims = await vehicleDataService.getTrims(pool, nhtsaYear, make.value, model.value);
      trimLevel = this.matchField(nhtsaTrim, trims);
    }

    // Match engine against dropdown options
    let engine: MatchedField<string> = { value: null, nhtsaValue: nhtsaEngine, confidence: 'none' };
    if (nhtsaYear && make.value && model.value && trimLevel.value && nhtsaEngine) {
      const engines = await vehicleDataService.getEngines(pool, nhtsaYear, make.value, model.value, trimLevel.value);
      engine = this.matchField(nhtsaEngine, engines);
    }

    // Match transmission against dropdown options
    let transmission: MatchedField<string> = { value: null, nhtsaValue: nhtsaTransmission, confidence: 'none' };
    if (nhtsaYear && make.value && model.value && trimLevel.value && nhtsaTransmission) {
      const transmissions = await vehicleDataService.getTransmissionsForTrim(pool, nhtsaYear, make.value, model.value, trimLevel.value);
      transmission = this.matchField(nhtsaTransmission, transmissions);
    }

    // Body type, drive type, and fuel type are display-only (no dropdown matching)
    const bodyType: MatchedField<string> = {
      value: null,
      nhtsaValue: nhtsaBodyType,
      confidence: 'none'
    };

    const driveType: MatchedField<string> = {
      value: null,
      nhtsaValue: nhtsaDriveType,
      confidence: 'none'
    };

    const fuelType: MatchedField<string> = {
      value: null,
      nhtsaValue: nhtsaFuelType,
      confidence: 'none'
    };

    return {
      year,
      make,
      model,
      trimLevel,
      bodyType,
      driveType,
      fuelType,
      engine,
      transmission
    };
  }

  /**
   * Match a value against dropdown options using fuzzy matching
   * Returns the matched dropdown value with confidence level
   * Matching order: exact -> normalized -> prefix -> contains
   */
  private matchField(nhtsaValue: string, options: string[]): MatchedField<string> {
    if (!nhtsaValue || options.length === 0) {
      return { value: null, nhtsaValue, confidence: 'none' };
    }

    const normalizedNhtsa = nhtsaValue.toLowerCase().trim();

    // Try exact case-insensitive match
    const exactMatch = options.find(opt => opt.toLowerCase().trim() === normalizedNhtsa);
    if (exactMatch) {
      return { value: exactMatch, nhtsaValue, confidence: 'high' };
    }

    // Try normalized comparison (remove special chars)
    const normalizeForCompare = (s: string) => s.toLowerCase().replace(/[^a-z0-9]/g, '');
    const normalizedNhtsaClean = normalizeForCompare(nhtsaValue);

    const normalizedMatch = options.find(opt => normalizeForCompare(opt) === normalizedNhtsaClean);
    if (normalizedMatch) {
      return { value: normalizedMatch, nhtsaValue, confidence: 'medium' };
    }

    // Try prefix match - option starts with NHTSA value
    const prefixMatch = options.find(opt => opt.toLowerCase().trim().startsWith(normalizedNhtsa));
    if (prefixMatch) {
      return { value: prefixMatch, nhtsaValue, confidence: 'medium' };
    }

    // Try contains match - option contains NHTSA value
    const containsMatch = options.find(opt => opt.toLowerCase().trim().includes(normalizedNhtsa));
    if (containsMatch) {
      return { value: containsMatch, nhtsaValue, confidence: 'medium' };
    }

    // No match found - return NHTSA value as hint with no match
    return { value: null, nhtsaValue, confidence: 'none' };
  }

  private toResponse(vehicle: Vehicle): VehicleResponse {
    return {
      id: vehicle.id,
      userId: vehicle.userId,
      vin: vehicle.vin,
      make: vehicle.make,
      model: vehicle.model,
      year: vehicle.year,
      engine: vehicle.engine,
      transmission: vehicle.transmission,
      trimLevel: vehicle.trimLevel,
      driveType: vehicle.driveType,
      fuelType: vehicle.fuelType,
      nickname: vehicle.nickname,
      color: vehicle.color,
      licensePlate: vehicle.licensePlate,
      odometerReading: vehicle.odometerReading,
      isActive: vehicle.isActive,
      createdAt: vehicle.createdAt.toISOString(),
      updatedAt: vehicle.updatedAt.toISOString(),
      imageUrl: vehicle.imageStorageKey ? `/api/vehicles/${vehicle.id}/image` : undefined,
    };
  }
}
