import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { FuelRates, FuelRatesDocument } from './schemas/fuel-rates.schema';
import {
  computeTravelAllowance,
  normalizeFuelRatesRecord,
  resolveTripDistanceKm,
  type BikeFuelRatesRecord,
  type CarFuelRatesRecord,
  type FuelRatesRecord,
} from './fuel-rates.util';

const SETTINGS_KEY = 'default';
const CACHE_MS = 30_000;

@Injectable()
export class FuelRatesService {
  private cached: { at: number; rates: FuelRatesRecord } | null = null;

  constructor(
    @InjectModel(FuelRates.name)
    private readonly fuelRatesModel: Model<FuelRatesDocument>,
  ) {}

  async getRates(): Promise<FuelRatesRecord> {
    if (this.cached && Date.now() - this.cached.at < CACHE_MS) {
      return this.cached.rates;
    }
    const doc = await this.fuelRatesModel
      .findOne({ key: SETTINGS_KEY })
      .lean()
      .exec();
    const rates = normalizeFuelRatesRecord(
      (doc as Record<string, unknown> | null) ?? undefined,
    );
    this.cached = { at: Date.now(), rates };
    return rates;
  }

  async updateRates(
    patch: {
      car?: Partial<CarFuelRatesRecord>;
      bike?: Partial<BikeFuelRatesRecord>;
      petrolPerKm?: number;
      dieselPerKm?: number;
      cngPerKm?: number;
    },
  ): Promise<FuelRatesRecord> {
    const current = await this.getRates();
    const next = normalizeFuelRatesRecord({
      car: { ...current.car, ...(patch.car as object | undefined) },
      bike: { ...current.bike, ...(patch.bike as object | undefined) },
      petrolPerKm: patch.petrolPerKm ?? current.car.petrolPerKm,
      dieselPerKm: patch.dieselPerKm ?? current.car.dieselPerKm,
      cngPerKm: patch.cngPerKm ?? current.car.cngPerKm,
    });
    await this.fuelRatesModel
      .findOneAndUpdate(
        { key: SETTINGS_KEY },
        { $set: { ...next, key: SETTINGS_KEY } },
        { upsert: true, new: true },
      )
      .exec();
    this.cached = null;
    return next;
  }

  async allowanceForTrip(trip: Record<string, unknown>) {
    const rates = await this.getRates();
    const legs = Array.isArray(trip.tripLegs)
      ? (trip.tripLegs as Record<string, unknown>[])
      : [];
    const distanceKm = resolveTripDistanceKm(trip, legs);
    const fuelType =
      (trip.fuelType as string | undefined) ??
      (trip.fuel_type as string | undefined);
    const vehicleType =
      (trip.vehicleType as string | undefined) ??
      (trip.vehicle_type as string | undefined);
    return {
      totalDistanceKm: distanceKm,
      ...computeTravelAllowance(distanceKm, vehicleType, fuelType, rates),
    };
  }
}
