import pumpReadingModel from "./pumpReading.model";
import { IPumpReading } from "./pumpReading.interface";
import fuelRequestModel from "../fuel-requests/fuelRequest.model";
import anomalyModel from "../anomalies/anomaly.model";


export class PumpReadingService{

    //Crear nueva lectura de bomba

    async create(
        data:IPumpReading
    ){
        data.gallonsDispensed=
        data.finalReading-
        data.initialReading;

        const pumpReading = new pumpReadingModel(data);

        return await pumpReading.save();
    }

    //Obtener todas las lecturas 

    async getAll(){

        return await pumpReadingModel
        .find()
        .populate("fuelPumpId")
        .populate("fuelTypeId")
        .populate("createdBy")
        .sort({
            readingDate:-1
        });
    }

    async getById(
        id:string
    ){

        return await pumpReadingModel
        .findById(id)
        .populate("fuelPumpId")
        .populate("fuelTypeId")
        .populate("createdBy")
    }

    async update (
        id:string,
        data:Partial<IPumpReading>
    ){
        if(
            data.initialReading !== undefined&&
            data.finalReading !== undefined
        ){
            data.gallonsDispensed =
            data.finalReading -
            data.initialReading;
        }

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

    async delete (
        id:string
    ){
        return await pumpReadingModel
        .findByIdAndDelete
    }

    //Calcular galones despachados

    async calculateDispensedGallons(
        id:string
    ){
        const reading =
        await pumpReadingModel.findById(id);

        if(!reading){
            throw new Error(
                "Lectura no encontrado"
            );
        }

        reading.gallonsDispensed =
        reading.finalReading -
        reading.initialReading;
        await reading.save();
        return reading.gallonsDispensed;
    }

    //Calcular galones registrados

    async calculateSystemDispensed(
        id:string
    ){
        const reading =
             await pumpReadingModel.findById(id);

        if(!reading){
            throw new Error (
                "Lectura no encontrada"
            );
        }

        const requests = await fuelRequestModel.find({

            fuelPumpId:reading.fuelPumpId,
            createdAt:{
                $gte:reading.readingDate,
                $lte:new Date()
            }
        });

        const total = requests.reduce(
            (sum, request) =>
                sum + request.gallonQuantity,
            0
        );

        reading.systemDispensed = total;
        await reading.save();
        return total;
    }

    //Calcular diferencia

    async calculateDifference(
        id:string
    ){
        const reading = await pumpReadingModel.findById(id);

        if (!reading) {
            throw new Error(
                "Lectura no encontrada"
            );
        }

        reading.difference =
        reading.gallonsDispensed -
        reading.systemDispensed;
        await reading.save();
        return reading.difference;
    }

    //Actualizar estado

    async updateStatus(
        id:string
    ){
        const reading = await pumpReadingModel.findById(id);

        if (!reading) {
            throw new Error(
                "Lectura no encontrada"
            );
        }

        if(
            reading.difference === 0
        ){
            reading.status = "CUADRADA";
        }

        else{
            reading.status = "CON_DIFERENCIA"
        }

        await reading.save();
        return reading.status;
    }

    async updateFuelRequests(
        id:string
    ){
        const reading = await pumpReadingModel.findById(id);

        if(!reading){
            throw new Error(
                "Lectura no encontrada"
            );
        }

        const requests = await fuelRequestModel.find ({
            fuelPumpId:reading.fuelPumpId,
            createdAt:{
                $gte:reading.readingDate,
                $lte:new Date()

            }
        });

        for (const request of requests) {
            request.pumpReading =
            reading._id as any;

            request.pumpDifference = 
            reading.difference;
            await request.save();

        }

        return requests;
    }

    //Crear anomalía por diferencencia

    async creataDifferenceAnomaly(
        id:string
    ){
        const reading = await pumpReadingModel.findById(id);

        if(!reading){
           throw new Error (
            "Lectura no encontrada"
            );
        }

        if (reading.difference ===0){
            return null;
        }

        const anomaly = new anomalyModel({
            vehicleId:0,

            anomalyType:
            "DIFERENCIA EN BOMBA",

            description:
            `La bomba presenta una diferencia de ${reading.difference} galones`,

            detectedBy: "SISTEMA",

            status: "ABIERTA",

            comments: "Generada automáticamente por el sistema"
        });

        return await anomaly.save();
    }

    async closeReading(
        id:string
    ){

        const reading = await pumpReadingModel.findById(id);

        if (!reading){
            throw new Error (
                "Lectura no encontrada"
            );
        }

        await this.calculateDispensedGallons(id);

        await this.calculateSystemDispensed(id);

        const difference = await this.calculateDifference(id);

        await this.updateStatus(id);

        await this.updateFuelRequests(id);

        //Crear anomalía

        if(difference !== 0){
            await this.creataDifferenceAnomaly(id);
        }

        return await pumpReadingModel
        .findById(id)
        .populate("fuelPumpId")
        .populate("fuelTypeId")
        .populate("createdBy")
    }
}