import OrderBookEntry from "../../../apiwrapper/orderbook/OrderBookEntry.js";
import TimedAssetData from "./TimedAssetData.js";

export default class TimedAssetDataMerger {
    /**
     * @type {TimedAssetData[]}
     */
    #slotsToMerge = []

    /**
     * @param {TimedAssetData} data 
     */
    push(data){
        this.#slotsToMerge.push(data);
    }

    /**
     * @param {number} expectedDuration duration of the new slot or null for sum of all given durations
     * @returns {TimedAssetData}
     */
    merge(expectedDuration = null){
        if(this.#slotsToMerge.length == 0){
            return null;
        }

        this.#slotsToMerge.sort((s1, s2) => s1.getStartTime() - s2.getStartTime());        

        const result = new TimedAssetData([0]);

        let shortestSlotDuration = this.#slotsToMerge[0].getEndTime() - this.#slotsToMerge[0].getStartTime();
        this.#slotsToMerge.forEach(s => {
            shortestSlotDuration = Math.min(shortestSlotDuration, s.getEndTime() - s.getStartTime());
        });
        let newSlotDuration = 0;

        let open = 0;
        let close = 0;
        let high = Number.MIN_VALUE;
        let low = Number.MAX_VALUE;
        let tradeCount = 0;
        let tradeVolume = 0;
        

        for(let i = this.#slotsToMerge.length - 1; i >= 0 && (expectedDuration == null || newSlotDuration < expectedDuration); i--){
            let factor = this.#slotsToMerge[i].getDuration() / shortestSlotDuration;
            if(expectedDuration != null && newSlotDuration + this.#slotsToMerge[i].getDuration() > expectedDuration){
                factor /= this.#slotsToMerge[i].getDuration() / (expectedDuration - newSlotDuration);
            }

            open = (open == 0 || factor >= 0.6) ? this.#slotsToMerge[i].getOpen() : open;
            close = close == 0 ? this.#slotsToMerge[i].getClose() : close;
            high = (high == 0 || factor >= 0.6) ? Math.max(this.#slotsToMerge[i].getHigh(), high) : high;
            low = (low == 0 || factor >= 0.6) ? Math.min(this.#slotsToMerge[i].getLow(), low) : low;
            tradeCount += factor < 1 ? this.#slotsToMerge[i].getTrades() * factor : this.#slotsToMerge[i].getTrades();
            tradeVolume += factor < 1 ? this.#slotsToMerge[i].getVolume() * factor : this.#slotsToMerge[i].getVolume();
            if(factor >= 0.6){
                result.pushBestAsk(this.#slotsToMerge[i].getBestAsk());
                result.pushBestBid(this.#slotsToMerge[i].getBestBid());
            }
        }

        result.open(this.#slotsToMerge[this.#slotsToMerge.length - 1].getEndTime() - newSlotDuration);
        result.setDuration(newSlotDuration);
        result.push(high, low, open, close);
        result.setTradeValues(Math.round(tradeCount), 0, tradeVolume);
        result.close(this.#slotsToMerge[this.#slotsToMerge.length - 1].getEndTime());

        return result;
    }
}