import { BadRequestException } from '@nestjs/common';
import { FuelType, VehicleType } from '../common/constants/enums';

export type CarFuelRatesRecord = {
  petrolPerKm: number;
  dieselPerKm: number;
  cngPerKm: number;
  electricPerKm: number;
};

export type BikeFuelRatesRecord = {
  petrolPerKm: number;
  electricPerKm: number;
};

export type FuelRatesRecord = {
  car: CarFuelRatesRecord;
  bike: BikeFuelRatesRecord;
};

function toRate(value: unknown): number {
  return Math.max(0, Number(value ?? 0) || 0);
}

export function normalizeFuelRatesRecord(
  input?: Partial<FuelRatesRecord> & Record<string, unknown> | null,
): FuelRatesRecord {
  const raw = input ?? {};
  const carRaw = (raw.car as Partial<CarFuelRatesRecord> | undefined) ?? {};
  const bikeRaw = (raw.bike as Partial<BikeFuelRatesRecord> | undefined) ?? {};

  return {
    car: {
      petrolPerKm: toRate(carRaw.petrolPerKm ?? raw.petrolPerKm),
      dieselPerKm: toRate(carRaw.dieselPerKm ?? raw.dieselPerKm),
      cngPerKm: toRate(carRaw.cngPerKm ?? raw.cngPerKm),
      electricPerKm: toRate(carRaw.electricPerKm),
    },
    bike: {
      petrolPerKm: toRate(bikeRaw.petrolPerKm),
      electricPerKm: toRate(bikeRaw.electricPerKm),
    },
  };
}

function isBikeVehicle(vehicleType: string | undefined | null): boolean {
  const v = vehicleType?.trim().toUpperCase();
  return v === VehicleType.BIKE || v === VehicleType.SCOOTER;
}

export function allowedFuelTypesForVehicle(
  vehicleType: string | undefined | null,
): FuelType[] {
  if (isBikeVehicle(vehicleType)) {
    return [FuelType.PETROL, FuelType.ELECTRIC];
  }
  return [FuelType.PETROL, FuelType.DIESEL, FuelType.CNG, FuelType.ELECTRIC];
}

export function assertFuelTypeForVehicle(
  vehicleType: VehicleType | undefined,
  fuelType: FuelType | undefined,
) {
  if (!vehicleType) return;
  const requiresFuel =
    vehicleType === VehicleType.CAR || isBikeVehicle(vehicleType);
  if (!requiresFuel) return;

  if (!fuelType) {
    throw new BadRequestException(
      vehicleType === VehicleType.CAR
        ? 'fuelType is required for car (petrol, diesel, cng, or electric)'
        : 'fuelType is required for two wheeler (petrol or electric)',
    );
  }

  const allowed = allowedFuelTypesForVehicle(vehicleType);
  if (!allowed.includes(fuelType)) {
    throw new BadRequestException(
      `Invalid fuelType ${fuelType} for vehicleType ${vehicleType}`,
    );
  }
}

export function rateForTrip(
  vehicleType: string | undefined | null,
  fuelType: string | undefined | null,
  rates: FuelRatesRecord,
): number | null {
  if (!fuelType) return null;
  const fuel = fuelType.trim().toUpperCase();

  if (isBikeVehicle(vehicleType)) {
    switch (fuel) {
      case FuelType.PETROL:
        return rates.bike.petrolPerKm;
      case FuelType.ELECTRIC:
        return rates.bike.electricPerKm;
      default:
        return null;
    }
  }

  switch (fuel) {
    case FuelType.PETROL:
      return rates.car.petrolPerKm;
    case FuelType.DIESEL:
      return rates.car.dieselPerKm;
    case FuelType.CNG:
      return rates.car.cngPerKm;
    case FuelType.ELECTRIC:
      return rates.car.electricPerKm;
    default:
      return null;
  }
}

export function resolveTripDistanceKm(
  trip: Record<string, unknown>,
  legs: Record<string, unknown>[] = [],
): number {
  if (legs.length > 0) {
    let sum = 0;
    for (const leg of legs) {
      const track = Number(leg.actualDistanceKmFromTrack ?? 0);
      const actual = Number(leg.actualDistanceKm ?? 0);
      const planned = Number(leg.plannedDistanceKm ?? 0);
      sum += track > 0 ? track : actual > 0 ? actual : planned;
    }
    if (sum > 0) return sum;
  }

  const km = Number(trip.totalDistanceKm ?? 0);
  if (km > 0) return km;

  const meters = Number(trip.totalDistance ?? 0);
  if (meters > 0) return meters / 1000;

  return 0;
}

export function computeTravelAllowance(
  distanceKm: number,
  vehicleType: string | undefined | null,
  fuelType: string | undefined | null,
  rates: FuelRatesRecord,
): { travelAllowance: number; fuelRatePerKm: number | null } {
  if (distanceKm <= 0) {
    return { travelAllowance: 0, fuelRatePerKm: null };
  }
  const rate = rateForTrip(vehicleType, fuelType, rates);
  if (rate == null || rate <= 0) {
    return { travelAllowance: 0, fuelRatePerKm: rate };
  }
  const amount = Math.round(distanceKm * rate * 100) / 100;
  return { travelAllowance: amount, fuelRatePerKm: rate };
}
