import fuelRequestModel from "./fuelRequest.model";
import { IFuelRequest } from "./fuelRequest.interface";

import { generateRequestNumber } from "../../utils/requestNumber";

import vehiclesConfigModel from "../vehicles-config/vehiclesConfig.model";
import anomalyModel from "../anomalies/anomaly.model";
import { IAnomaly } from "../anomalies/anomaly.interface";

export class FuelRequestService {
    //Obtener todas las requisiciones

    async getAll() {
        return await fuelRequestModel
            .find()
            .populate("fuelPumpId")
            .populate("fuelTypeId")
            .populate("createdBy")
            .populate("authorizedBy")
            .sort({ createdAt: -1 });
    }

    //Obtener reauisición por ID

    async getById(
        id:string
    ) {

        return await fuelRequestModel
            .findById(id)
            .populate("fuelPumpId")
            .populate("fuelTypeId")
            .populate("createdBy")
            .populate("authorizedBy");

    }

    //Crear una nueva requisición

    async create (
        data:IFuelRequest
    ){
        //Generar número automático
        data.requestNumber = generateRequestNumber();

        //Calcular distancia recorrida
        data.distanceTraveled = data.currentMileage - data.previousMileage;

        //Calcular monto total
        data.totalAmount = data.gallonQuantity * data.pricePerGallon;

        //Estado inicial
        data.status = "PENDIENTE";

        //Crear documento
        const request = new fuelRequestModel(data);

        //Guardar en DB
        return await request.save();

    }

    async update(
        id:string,
        data:Partial<IFuelRequest>
    ){
        //Recalcular distancia
        if(data.currentMileage !== undefined &&
            data.previousMileage !== undefined
        ){
            data.distanceTraveled =
            data.currentMileage -
            data.previousMileage;
        }

        //Recalcular monto
        if(
            data.gallonQuantity !== undefined &&
            data.pricePerGallon !== undefined
        ){
            data.totalAmount =
            data.gallonQuantity *
            data.pricePerGallon;
        }

        return await fuelRequestModel
        .findByIdAndUpdate(
            id,
            data,
            {
                new:true
            }
        );
    }

    //Eliminar requisición

    async delete(
        id:string
    ){

        return await fuelRequestModel
        .findByIdAndDelete(id);
    }

    private async detectAnomalies(
        fuelRequest:any
    ){
        await this.validateMileage(
            fuelRequest
        );

        await this.validateFuelConsumption(
            fuelRequest
        );

        await this.validateTankCapacity(
            fuelRequest
        );

        await this.validatePreviousFuelRequest(
            fuelRequest
        );
    }

    private async validateMileage(
        data:any
    ){

        //Kilometraje menor que el anterior
        if (
            data.currentMileage <
            data.previousMileage
        ){
            await this.createAnomaly(
                data,
                "KILOMETRAJE FUERA DE RANGO",
                "El kilometraje actual es menor que el anterior"
            );
        }

        //Odomentro en mal estado
        if(data.currentMileage === data.previousMileage){
            await this.createAnomaly(
                data,
                "ODOMETRO EN MAL ESTADO",
                "El kilometraje no cambió respecto al anterior"
            );
        }

        //Diferencia mayor a 500km
        if(data.distanceTraveled>500){
            await this.createAnomaly(
                data,
                "KILOMETRAJE FUERA DE RANGO",
                "La distancia recorrida supera los 500 kilometros"
            );
        }
    }

    
    //Validar rendimiento de combustible
    private async validateFuelConsumption(
        data:any
    ){
        //Evitar división entre 0}
        if(
            data.gallonQuantity <=0
        ){
            return;
        }

        //Calcular distancia recorrida

        const distance =
        data.currentMileage - data.previousMileage;

        //Calcular rendimiento

        const performance =

        distance/
        data.gallonQuantity;

        //Bajo rendimiento

        if (performance < 10){
            await this.createAnomaly(
                data,
                "RENDIMIENTO BAJO",
                `El vehículo tiene un rendimiento de ${performance.toFixed(2)} km por galón.`
            )
        }
    }

    //Validar capacidad del tanque
    private async validateTankCapacity(
        data:any
    ){
        const vehicleConfig = await vehiclesConfigModel.findOne({
            vehicleid:data.vehicleId
        });

        //Sino existe configuración no validar
        if(!vehicleConfig){
            return;
        }

        //Validar capacidad del tanque

        if(
            data.gallonQuantity >
            vehicleConfig.tankcapacity
        ){
            await this.createAnomaly(
                data,
                "CONSUMO ELEVADO",
                `Se solicitaron ${data.gallonQuantity} galones, pero la capacidad del tanque es de ${vehicleConfig.tankcapacity} galones.`
            )
        }
    }

    // Validar contra la carga anterior
    
    private async validatePreviousFuelRequest(
        data:any
    ) {

        // Buscar la última requisición del vehículo
        const previousRequest =
            await fuelRequestModel
                .findOne({

                    vehicleId: data.vehicleId,

                    _id: { $ne: data._id }

                })
                .sort({
                    createdAt: -1
                });

        // Si no existe una carga anterior, salir
        if (!previousRequest) {

            return;

        }

        // Calcular diferencia de galones
        const difference = Math.abs(

            data.gallonQuantity -

            previousRequest.gallonQuantity

        );

        // Si la diferencia es mayor a 5 galones
        if (difference > 5) {

            await this.createAnomaly(

                data,

                "CONSUMO ELEVADO",

                `La carga actual difiere en ${difference} galones respecto a la carga anterior.`

            );

        }

    }


    //Crear anomalía
    private async createAnomaly(

        fuelRequest: any,

        anomalyType: IAnomaly["anomalyType"],

        description: string

    ) {

        return await anomalyModel.create({

            vehicleId: fuelRequest.vehicleId,

            employeeId: fuelRequest.employeeId,

            fuelRequestId: fuelRequest._id,

            anomalyType,

            description,

            detectedBy: "SISTEMA",

            status: "ABIERTA",

            comments:
                "Anomalía generada automáticamente por el sistema."

        });

    }
}