# Phase 2: Enhanced Business Logic

## Overview
Implement sophisticated business logic for fuel type/grade relationships, Imperial/Metric conversion system, enhanced MPG calculations, and advanced validation rules.

## Prerequisites
- ✅ Phase 1 completed (database schema and core types)
- Database migration deployed and tested
- Core validation logic functional

## Fuel Type/Grade Dynamic System

### Fuel Grade Service

**File**: `backend/src/features/fuel-logs/domain/fuel-grade.service.ts`

```typescript
import { FuelType, FuelGrade, GasolineFuelGrade, DieselFuelGrade } from './fuel-logs.types';

export interface FuelGradeOption {
  value: FuelGrade;
  label: string;
  description?: string;
}

export class FuelGradeService {
  
  static getFuelGradeOptions(fuelType: FuelType): FuelGradeOption[] {
    switch (fuelType) {
      case FuelType.GASOLINE:
        return [
          { value: GasolineFuelGrade.REGULAR_87, label: '87 (Regular)', description: 'Regular unleaded gasoline' },
          { value: GasolineFuelGrade.MIDGRADE_88, label: '88 (Mid-Grade)', description: 'Mid-grade gasoline' },
          { value: GasolineFuelGrade.MIDGRADE_89, label: '89 (Mid-Grade Plus)', description: 'Mid-grade plus gasoline' },
          { value: GasolineFuelGrade.PREMIUM_91, label: '91 (Premium)', description: 'Premium gasoline' },
          { value: GasolineFuelGrade.PREMIUM_93, label: '93 (Premium Plus)', description: 'Premium plus gasoline' }
        ];
      
      case FuelType.DIESEL:
        return [
          { value: DieselFuelGrade.DIESEL_1, label: '#1 Diesel', description: 'Light diesel fuel' },
          { value: DieselFuelGrade.DIESEL_2, label: '#2 Diesel', description: 'Standard diesel fuel' }
        ];
      
      case FuelType.ELECTRIC:
        return []; // No grades for electric
      
      default:
        return [];
    }
  }
  
  static isValidGradeForFuelType(fuelType: FuelType, fuelGrade?: FuelGrade): boolean {
    if (!fuelGrade) {
      return fuelType === FuelType.ELECTRIC; // Only electric allows null grade
    }
    
    const validGrades = this.getFuelGradeOptions(fuelType).map(option => option.value);
    return validGrades.includes(fuelGrade);
  }
  
  static getDefaultGrade(fuelType: FuelType): FuelGrade {
    switch (fuelType) {
      case FuelType.GASOLINE:
        return GasolineFuelGrade.REGULAR_87;
      case FuelType.DIESEL:
        return DieselFuelGrade.DIESEL_2;
      case FuelType.ELECTRIC:
        return null;
      default:
        return null;
    }
  }
}
```

## Imperial/Metric Conversion System

### Unit Conversion Service

**File**: `backend/src/features/fuel-logs/domain/unit-conversion.service.ts`

```typescript
import { UnitSystem, UnitConversion } from './fuel-logs.types';

export interface ConversionFactors {
  // Volume conversions
  gallonsToLiters: number;
  litersToGallons: number;
  
  // Distance conversions  
  milesToKilometers: number;
  kilometersToMiles: number;
}

export class UnitConversionService {
  
  private static readonly FACTORS: ConversionFactors = {
    gallonsToLiters: 3.78541,
    litersToGallons: 0.264172,
    milesToKilometers: 1.60934,
    kilometersToMiles: 0.621371
  };
  
  static getUnitLabels(unitSystem: UnitSystem): UnitConversion {
    switch (unitSystem) {
      case UnitSystem.IMPERIAL:
        return {
          fuelUnits: 'gallons',
          distanceUnits: 'miles',
          efficiencyUnits: 'mpg'
        };
      case UnitSystem.METRIC:
        return {
          fuelUnits: 'liters',
          distanceUnits: 'kilometers', 
          efficiencyUnits: 'L/100km'
        };
    }
  }
  
  // Volume conversions
  static convertFuelUnits(value: number, fromSystem: UnitSystem, toSystem: UnitSystem): number {
    if (fromSystem === toSystem) return value;
    
    if (fromSystem === UnitSystem.IMPERIAL && toSystem === UnitSystem.METRIC) {
      return value * this.FACTORS.gallonsToLiters; // gallons to liters
    }
    
    if (fromSystem === UnitSystem.METRIC && toSystem === UnitSystem.IMPERIAL) {
      return value * this.FACTORS.litersToGallons; // liters to gallons
    }
    
    return value;
  }
  
  // Distance conversions
  static convertDistance(value: number, fromSystem: UnitSystem, toSystem: UnitSystem): number {
    if (fromSystem === toSystem) return value;
    
    if (fromSystem === UnitSystem.IMPERIAL && toSystem === UnitSystem.METRIC) {
      return value * this.FACTORS.milesToKilometers; // miles to kilometers
    }
    
    if (fromSystem === UnitSystem.METRIC && toSystem === UnitSystem.IMPERIAL) {
      return value * this.FACTORS.kilometersToMiles; // kilometers to miles
    }
    
    return value;
  }
  
  // Efficiency calculations
  static calculateEfficiency(distance: number, fuelUnits: number, unitSystem: UnitSystem): number {
    if (fuelUnits <= 0) return 0;
    
    switch (unitSystem) {
      case UnitSystem.IMPERIAL:
        return distance / fuelUnits; // miles per gallon
      case UnitSystem.METRIC:
        return (fuelUnits / distance) * 100; // liters per 100 kilometers
      default:
        return 0;
    }
  }
  
  // Convert efficiency between unit systems
  static convertEfficiency(efficiency: number, fromSystem: UnitSystem, toSystem: UnitSystem): number {
    if (fromSystem === toSystem) return efficiency;
    
    if (fromSystem === UnitSystem.IMPERIAL && toSystem === UnitSystem.METRIC) {
      // MPG to L/100km: L/100km = 235.214 / MPG
      return efficiency > 0 ? 235.214 / efficiency : 0;
    }
    
    if (fromSystem === UnitSystem.METRIC && toSystem === UnitSystem.IMPERIAL) {
      // L/100km to MPG: MPG = 235.214 / (L/100km)
      return efficiency > 0 ? 235.214 / efficiency : 0;
    }
    
    return efficiency;
  }
}
```

## Enhanced MPG/Efficiency Calculations

### Efficiency Calculation Service

**File**: `backend/src/features/fuel-logs/domain/efficiency-calculation.service.ts`

```typescript
import { FuelLog, UnitSystem } from './fuel-logs.types';
import { UnitConversionService } from './unit-conversion.service';

export interface EfficiencyResult {
  value: number;
  unitSystem: UnitSystem;
  label: string;
  calculationMethod: 'odometer' | 'trip_distance';
}

export class EfficiencyCalculationService {
  
  /**
   * Calculate efficiency for a fuel log entry
   */
  static calculateEfficiency(
    currentLog: Partial<FuelLog>,
    previousLog: FuelLog | null,
    userUnitSystem: UnitSystem
  ): EfficiencyResult | null {
    
    // Determine calculation method and distance
    let distance: number;
    let calculationMethod: 'odometer' | 'trip_distance';
    
    if (currentLog.tripDistance) {
      // Use trip distance directly
      distance = currentLog.tripDistance;
      calculationMethod = 'trip_distance';
    } else if (currentLog.odometerReading && previousLog?.odometerReading) {
      // Calculate from odometer difference
      distance = currentLog.odometerReading - previousLog.odometerReading;
      calculationMethod = 'odometer';
      
      if (distance <= 0) {
        return null; // Invalid distance
      }
    } else {
      return null; // Cannot calculate efficiency
    }
    
    if (!currentLog.fuelUnits || currentLog.fuelUnits <= 0) {
      return null; // Invalid fuel amount
    }
    
    // Calculate efficiency in user's preferred unit system
    const efficiency = UnitConversionService.calculateEfficiency(
      distance,
      currentLog.fuelUnits,
      userUnitSystem
    );
    
    const unitLabels = UnitConversionService.getUnitLabels(userUnitSystem);
    
    return {
      value: efficiency,
      unitSystem: userUnitSystem,
      label: unitLabels.efficiencyUnits,
      calculationMethod
    };
  }
  
  /**
   * Calculate average efficiency for a set of fuel logs
   */
  static calculateAverageEfficiency(
    fuelLogs: FuelLog[],
    userUnitSystem: UnitSystem
  ): EfficiencyResult | null {
    
    const validLogs = fuelLogs.filter(log => log.mpg && log.mpg > 0);
    
    if (validLogs.length === 0) {
      return null;
    }
    
    // Convert all efficiencies to user's unit system and average
    const efficiencies = validLogs.map(log => {
      // Assume stored efficiency is in Imperial (MPG)
      return UnitConversionService.convertEfficiency(
        log.mpg!,
        UnitSystem.IMPERIAL,
        userUnitSystem
      );
    });
    
    const averageEfficiency = efficiencies.reduce((sum, eff) => sum + eff, 0) / efficiencies.length;
    const unitLabels = UnitConversionService.getUnitLabels(userUnitSystem);
    
    return {
      value: averageEfficiency,
      unitSystem: userUnitSystem,
      label: unitLabels.efficiencyUnits,
      calculationMethod: 'odometer' // Mixed, but default to odometer
    };
  }
  
  /**
   * Calculate total distance traveled from fuel logs
   */
  static calculateTotalDistance(fuelLogs: FuelLog[], userUnitSystem: UnitSystem): number {
    let totalDistance = 0;
    
    for (let i = 1; i < fuelLogs.length; i++) {
      const current = fuelLogs[i];
      const previous = fuelLogs[i - 1];
      
      if (current.tripDistance) {
        // Use trip distance if available
        totalDistance += current.tripDistance;
      } else if (current.odometerReading && previous.odometerReading) {
        // Calculate from odometer difference
        const distance = current.odometerReading - previous.odometerReading;
        if (distance > 0) {
          totalDistance += distance;
        }
      }
    }
    
    return totalDistance;
  }
}
```

## Advanced Validation Rules

### Enhanced Validation Service

**File**: `backend/src/features/fuel-logs/domain/enhanced-validation.service.ts`

```typescript
import { CreateFuelLogRequest, UpdateFuelLogRequest, FuelType, UnitSystem } from './fuel-logs.types';
import { FuelGradeService } from './fuel-grade.service';

export interface ValidationResult {
  isValid: boolean;
  errors: string[];
  warnings: string[];
}

export class EnhancedValidationService {
  
  static validateFuelLogData(
    data: CreateFuelLogRequest | UpdateFuelLogRequest,
    userUnitSystem: UnitSystem
  ): ValidationResult {
    
    const errors: string[] = [];
    const warnings: string[] = [];
    
    // Distance requirement validation
    this.validateDistanceRequirement(data, errors);
    
    // Fuel system validation
    this.validateFuelSystem(data, errors);
    
    // Numeric value validation
    this.validateNumericValues(data, errors, warnings);
    
    // DateTime validation
    this.validateDateTime(data, errors);
    
    // Business logic validation
    this.validateBusinessRules(data, errors, warnings, userUnitSystem);
    
    return {
      isValid: errors.length === 0,
      errors,
      warnings
    };
  }
  
  private static validateDistanceRequirement(
    data: CreateFuelLogRequest | UpdateFuelLogRequest,
    errors: string[]
  ): void {
    const hasOdometer = data.odometerReading && data.odometerReading > 0;
    const hasTripDistance = data.tripDistance && data.tripDistance > 0;
    
    if (!hasOdometer && !hasTripDistance) {
      errors.push('Either odometer reading or trip distance is required');
    }
    
    if (hasOdometer && hasTripDistance) {
      errors.push('Cannot specify both odometer reading and trip distance');
    }
  }
  
  private static validateFuelSystem(
    data: CreateFuelLogRequest | UpdateFuelLogRequest,
    errors: string[]
  ): void {
    if (!data.fuelType) return;
    
    // Validate fuel type
    if (!Object.values(FuelType).includes(data.fuelType)) {
      errors.push(`Invalid fuel type: ${data.fuelType}`);
      return;
    }
    
    // Validate fuel grade for fuel type
    if (!FuelGradeService.isValidGradeForFuelType(data.fuelType, data.fuelGrade)) {
      errors.push(`Invalid fuel grade '${data.fuelGrade}' for fuel type '${data.fuelType}'`);
    }
  }
  
  private static validateNumericValues(
    data: CreateFuelLogRequest | UpdateFuelLogRequest,
    errors: string[],
    warnings: string[]
  ): void {
    
    // Positive value checks
    if (data.fuelUnits !== undefined && data.fuelUnits <= 0) {
      errors.push('Fuel units must be positive');
    }
    
    if (data.costPerUnit !== undefined && data.costPerUnit <= 0) {
      errors.push('Cost per unit must be positive');
    }
    
    if (data.odometerReading !== undefined && data.odometerReading <= 0) {
      errors.push('Odometer reading must be positive');
    }
    
    if (data.tripDistance !== undefined && data.tripDistance <= 0) {
      errors.push('Trip distance must be positive');
    }
    
    // Reasonable value warnings
    if (data.fuelUnits && data.fuelUnits > 100) {
      warnings.push('Fuel amount seems unusually high (>100 units)');
    }
    
    if (data.costPerUnit && data.costPerUnit > 10) {
      warnings.push('Cost per unit seems unusually high (>$10)');
    }
    
    if (data.tripDistance && data.tripDistance > 1000) {
      warnings.push('Trip distance seems unusually high (>1000 miles)');
    }
  }
  
  private static validateDateTime(
    data: CreateFuelLogRequest | UpdateFuelLogRequest,
    errors: string[]
  ): void {
    if (!data.dateTime) return;
    
    const date = new Date(data.dateTime);
    const now = new Date();
    
    if (isNaN(date.getTime())) {
      errors.push('Invalid date/time format');
      return;
    }
    
    if (date > now) {
      errors.push('Cannot create fuel logs in the future');
    }
    
    // Check if date is too far in the past (>2 years)
    const twoYearsAgo = new Date(now.getTime() - (2 * 365 * 24 * 60 * 60 * 1000));
    if (date < twoYearsAgo) {
      errors.push('Fuel log date cannot be more than 2 years in the past');
    }
  }
  
  private static validateBusinessRules(
    data: CreateFuelLogRequest | UpdateFuelLogRequest,
    errors: string[],
    warnings: string[],
    userUnitSystem: UnitSystem
  ): void {
    
    // Electric vehicle specific validation
    if (data.fuelType === FuelType.ELECTRIC) {
      if (data.costPerUnit && data.costPerUnit > 0.50) {
        warnings.push('Cost per kWh seems high for electric charging');
      }
    }
    
    // Efficiency warning calculation
    if (data.fuelUnits && data.tripDistance) {
      const estimatedMPG = data.tripDistance / data.fuelUnits;
      
      if (userUnitSystem === UnitSystem.IMPERIAL) {
        if (estimatedMPG < 5) {
          warnings.push('Calculated efficiency is very low (<5 MPG)');
        } else if (estimatedMPG > 50) {
          warnings.push('Calculated efficiency is very high (>50 MPG)');
        }
      }
    }
    
    // Cost validation
    if (data.fuelUnits && data.costPerUnit) {
      const calculatedTotal = data.fuelUnits * data.costPerUnit;
      // Allow 1 cent tolerance for rounding
      if (Math.abs(calculatedTotal - (data.totalCost || calculatedTotal)) > 0.01) {
        warnings.push('Total cost does not match fuel units × cost per unit');
      }
    }
  }
}
```

## User Settings Integration

### User Settings Service Interface

**File**: `backend/src/features/fuel-logs/external/user-settings.service.ts`

```typescript
import { UnitSystem } from '../domain/fuel-logs.types';

export interface UserSettings {
  unitSystem: UnitSystem;
  defaultFuelType?: string;
  currencyCode: string;
  timeZone: string;
}

export class UserSettingsService {
  
  /**
   * Get user's unit system preference
   * TODO: Integrate with actual user settings service
   */
  static async getUserUnitSystem(userId: string): Promise<UnitSystem> {
    // Placeholder implementation - replace with actual user settings lookup
    // For now, default to Imperial
    return UnitSystem.IMPERIAL;
  }
  
  /**
   * Get full user settings for fuel logs
   */
  static async getUserSettings(userId: string): Promise<UserSettings> {
    // Placeholder implementation
    return {
      unitSystem: await this.getUserUnitSystem(userId),
      currencyCode: 'USD',
      timeZone: 'America/New_York'
    };
  }
  
  /**
   * Update user's unit system preference
   */
  static async updateUserUnitSystem(userId: string, unitSystem: UnitSystem): Promise<void> {
    // Placeholder implementation - replace with actual user settings update
    console.log(`Update user ${userId} unit system to ${unitSystem}`);
  }
}
```

## Implementation Tasks

### Fuel Type/Grade System
1. ✅ Create FuelGradeService with dynamic grade options
2. ✅ Implement fuel type validation logic
3. ✅ Add default grade selection
4. ✅ Create grade validation for each fuel type

### Unit Conversion System
1. ✅ Create UnitConversionService with conversion factors
2. ✅ Implement volume/distance conversions
3. ✅ Add efficiency calculation methods
4. ✅ Create unit label management

### Enhanced Calculations
1. ✅ Create EfficiencyCalculationService
2. ✅ Implement trip distance vs odometer logic
3. ✅ Add average efficiency calculations
4. ✅ Create total distance calculations

### Advanced Validation
1. ✅ Create EnhancedValidationService
2. ✅ Implement comprehensive validation rules
3. ✅ Add business logic validation
4. ✅ Create warning system for unusual values

### User Settings Integration
1. ✅ Create UserSettingsService interface
2. ✅ Add unit system preference lookup
3. ✅ Prepare for actual user settings integration

## Testing Requirements

### Unit Tests Required

```typescript
// Test fuel grade service
describe('FuelGradeService', () => {
  it('should return correct grades for gasoline', () => {
    const grades = FuelGradeService.getFuelGradeOptions(FuelType.GASOLINE);
    expect(grades).toHaveLength(5);
    expect(grades[0].value).toBe('87');
  });
  
  it('should validate grades correctly', () => {
    expect(FuelGradeService.isValidGradeForFuelType(FuelType.GASOLINE, '87')).toBe(true);
    expect(FuelGradeService.isValidGradeForFuelType(FuelType.GASOLINE, '#1')).toBe(false);
  });
});

// Test unit conversion service
describe('UnitConversionService', () => {
  it('should convert gallons to liters correctly', () => {
    const liters = UnitConversionService.convertFuelUnits(10, UnitSystem.IMPERIAL, UnitSystem.METRIC);
    expect(liters).toBeCloseTo(37.85, 2);
  });
  
  it('should calculate MPG correctly', () => {
    const mpg = UnitConversionService.calculateEfficiency(300, 10, UnitSystem.IMPERIAL);
    expect(mpg).toBe(30);
  });
});

// Test efficiency calculation service
describe('EfficiencyCalculationService', () => {
  it('should calculate efficiency from trip distance', () => {
    const result = EfficiencyCalculationService.calculateEfficiency(
      { tripDistance: 300, fuelUnits: 10 },
      null,
      UnitSystem.IMPERIAL
    );
    expect(result?.value).toBe(30);
    expect(result?.calculationMethod).toBe('trip_distance');
  });
});

// Test validation service
describe('EnhancedValidationService', () => {
  it('should require distance input', () => {
    const result = EnhancedValidationService.validateFuelLogData(
      { fuelType: FuelType.GASOLINE, fuelUnits: 10, costPerUnit: 3.50 },
      UnitSystem.IMPERIAL
    );
    expect(result.isValid).toBe(false);
    expect(result.errors).toContain('Either odometer reading or trip distance is required');
  });
});
```

## Success Criteria

### Phase 2 Complete When:
- ✅ Fuel type/grade system fully functional
- ✅ Imperial/Metric conversions working correctly
- ✅ Enhanced efficiency calculations implemented
- ✅ Advanced validation rules active
- ✅ User settings integration interface ready
- ✅ All business logic unit tested
- ✅ Integration with existing fuel logs service

### Ready for Phase 3 When:
- All business logic services tested and functional
- Unit conversion system verified accurate
- Fuel grade system working correctly
- Validation rules catching all edge cases
- Ready for API integration

---

**Next Phase**: [Phase 3 - API & Backend Implementation](FUEL-LOGS-PHASE-3.md)