
const { ObjectId } = require('mongodb');
const connectDb = require("./db");
const { LotDb } = require("./lotDb");
const lotDb = new LotDb();

const SaleDb = class
{
    constructor()
    {
        this.getCollection();
    }

    async getCollection()
    {
        const db = await connectDb();
        if (!db) {
            throw new Error('Database not connected');
        }
        this.collection = db.collection("Sales");
    }

    // CRUD
    async get(id)
    {
        let result = await this.collection.findOne({_id: new ObjectId(id)});
        return result;
    }

    async post(newDocument)
    {
        delete newDocument._id;
        let result = await this.collection.insertOne(newDocument);
        return result;
    }

    async put(id, data)
    {
        let result = await this.collection.updateOne({_id: new ObjectId(id)}, {$set: data});
        return result;
    }

    async remove(id)
    {
        let result = await this.collection.deleteOne({_id: new ObjectId(id)});   
        return result;
    }

    // Fucntions

    async getAll()
    {
        let result = await this.collection.find({}).toArray();
        return result;
    }

    async getByUrl(url)
    {
        let result = await this.collection.findOne({url: url});
        return result;
    }

    async getByIDPlatform(idSalePlatform, platformName)
    {
        let result = await this.collection.findOne({idPlatform: String(idSalePlatform), platform: String(platformName)});        
        return result;
    }

    async processStats(id)
    {
        let Sale = await this.get(id);
        
        if(!Sale){
            console.error("Sale not found");
            throw new Error("Sale not found");
        }
        console.log(Sale);
        let Lots = await lotDb.getBySaleId(Sale._id.toString(),Sale.platform);

        let TimestampInSecond = (timestamp) => {
            const stringTimestamp = String(timestamp);
            if (stringTimestamp.length === 13) {
            return timestamp / 1000;
            } else if (stringTimestamp.length === 10) {
            return timestamp;
            } else {
            return 0;
            }
        }

        // Create an array to hold the updated lots
        let updatedLots = [];
        let bidsDuration = 0;

        // process each lot
        for (let lot of Lots) {
            let highestBid, duration, percentageAboveUnderLow, percentageAboveUnderHigh = 0;

            // if bid
            let nbrBids = 0;
            if (Array.isArray(lot.Bids)) {

            nbrBids = lot.Bids.length;

            highestBid = lot.Bids.reduce((prev, current) => (prev.amount > current.amount) ? prev : current).amount;   
            let startTime = TimestampInSecond(lot.Bids[0].timestamp);  
            let endTime = TimestampInSecond(lot.Bids[lot.Bids.length-1].timestamp);   
            duration = endTime - startTime;    

            // total time of bids
            bidsDuration += duration;

            duration = duration.toFixed(0);
            }

            // if auctioned
            percentageAboveUnderLow = 0;
            percentageAboveUnderHigh = 0;
            if (lot.auctioned) {
            
            if(lot.EstimateLow){
                percentageAboveUnderLow = ((lot.auctioned.amount - lot.EstimateLow) / lot.EstimateLow) * 100;
            }
            
            if(lot.EstimateHigh){
                percentageAboveUnderHigh = ((lot.auctioned.amount - lot.EstimateHigh) / lot.EstimateHigh) * 100;
            }
            }

            let lotPostProcessing = {
            nbrBids: nbrBids,   
            highestBid: highestBid,
            duration: duration,
            percentageAboveUnderLow: percentageAboveUnderLow.toFixed(0),
            percentageAboveUnderHigh: percentageAboveUnderHigh.toFixed(0)
            }
            lot.postProcessing = lotPostProcessing;        
            await lotDb.put(lot._id, lot);
            
            // Add the updated lot to the array
            updatedLots.push(lot);
        }

        // refresh with postprocess datas
        Lots = updatedLots;

        
        let startTime = 0;
        if (Array.isArray(Lots[0].Bids)) {
            startTime = TimestampInSecond(Lots[0].Bids[0].timestamp);
        }else{
            startTime = TimestampInSecond(Lots[0].timestamp);
        }
        
        let LastBid = [...Lots].reverse().find(lot => lot.auctioned !== undefined);
        
        let endTime = 0;
        if (Array.isArray(LastBid.Bids)) {
            endTime = TimestampInSecond(LastBid.Bids[LastBid.Bids.length-1].timestamp);    
        }else{
            endTime = TimestampInSecond(LastBid.timestamp);
        }      
        console.log("Start Time: "+startTime);
        console.log("End Time: "+endTime);

        let duration = (endTime-startTime).toFixed(0);

        let totalAmount = 0;
        let unsoldLots = 0;
        for (let lot of Lots) {
            if (lot.auctioned) {          
            totalAmount += lot.auctioned.amount;
            } else {
            unsoldLots++;
            }
        }

        function calculateMedian(array) {
            array.sort((a, b) => a - b);
            let middleIndex = Math.floor(array.length / 2);
        
            if (array.length % 2 === 0) { // array has an even length
                return (array[middleIndex - 1] + array[middleIndex]) / 2;
            } else { // array has an odd length
                return array[middleIndex];
            }
        }
        const amounts = Lots.map(lot => lot.auctioned?.amount).filter(Boolean);
            
        //console.error(Lots);
        let postProcessing = {
            nbrLots: Lots.length,   
            duration: duration,
            bidsDuration: bidsDuration.toFixed(0),
            durationPerLots: (duration/Lots.length).toFixed(0),
            totalAmount: totalAmount,
            averageAmount: (totalAmount/Lots.length).toFixed(2),
            medianAmount: calculateMedian(amounts).toFixed(2),
            minAmount: Math.min(...amounts).toFixed(2),
            maxAmount: Math.max(...amounts).toFixed(2),
            unsoldLots: unsoldLots,
            unsoldPercentage: ((unsoldLots/Lots.length)*100).toFixed(2)
        }

        console.log(postProcessing);

        Sale.postProcessing = postProcessing;
        await this.put(Sale._id, Sale);
    }
}

module.exports = { SaleDb };