import TradeEvent from "../../../apiwrapper/event/TradeEvent.js";
import OrderBookEntry from "../../../apiwrapper/orderbook/OrderBookEntry.js";

export default class AggregatedDataPoint {

    /**
     * @type {number}
     */
    startTime = 0;

    /**
     * @type {number}
     */
    endTime = 0;

    /**
     * @type {boolean}
     */
    hasValues = false;

    /**
     * @type {number}
     */
    duration = 0;

    /**
     * @type {number}
     */
    tradeCount = 0;

    /**
     * @type {number}
     */
    tradeVolume = 0;

    /**
     * @type {number}
     */
    minPrice = 0;

    /**
     * @type {number}
     */
    maxPrice = 0;

    /**
     * @type {number}
     */
    avgPrice = 0;

    /**
     * @type {number}
     */
    startPrice = 0;

    /**
     * @type {number}
     */
    endPrice = 0;

    /**
     * @type {OrderBookEntry}
     */
    bestAsk = 0;

    /**
     * @type {OrderBookEntry}
     */
    bestBid = 0;

    /**
     * @type {number}
     */
    peakStarts = 0;

    /**
     * @type {number}
     */
    peakEnds = 0;

    /**
     * @type {number[]}
     */
    #priceValues = [];

    /**
     * @param {number} startTime 
     * @param {number} duration 
     */
    constructor(startTime, duration){
        this.startTime = startTime;
        this.duration = duration;
    }

    /**
     * @param {OrderBookEntry} ask 
     */
    pushAsk(ask){
        if(this.bestAsk == null || this.bestAsk.price < ask.price){
            this.bestAsk = ask;
        }
    }

    /**
     * @param {OrderBookEntry} bid 
     */
    pushBid(bid){
        if(!this.hasValues){
            this.startPrice = bid.price;
        }
        this.hasValues = true;
        this.minPrice = Math.min(this.minPrice, bid.price);
        this.maxPrice = Math.max(this.maxPrice = bid.price);
        this.endPrice = bid.price;
        this.#priceValues.push(bid.price);
        if(this.bestBid == null || this.bestBid.price < bid.price){
            this.bestBid = bid;
        }
    }

    /**
     * @param {TradeEvent} trade 
     */
    pushTrade(trade){
        this.tradeCount ++;
        this.tradeVolume += trade.quantity;
    }

    /**
     * @param {number} tradeCount 
     * @param {number} tradeVolume 
     */
    addTrades(tradeCount, tradeVolume){
        this.tradeCount += tradeCount;
        this.tradeVolume += tradeVolume;
    }

    /**
     * @param {number} endTime 
     */
    end(endTime){
        this.endTime = endTime;
        let priceSum = 0;
        this.#priceValues.forEach(p => priceSum += p);
        this.avgPrice = priceSum / this.#priceValues.length;
        this.#priceValues = [];
    }

    clone(){
        const dp = new AggregatedDataPoint(this.startTime, this.duration);
        dp.startPrice = this.startPrice;
        dp.endPrice = this.endPrice;
        dp.avgPrice = this.avgPrice;
        dp.maxPrice = this.maxPrice;
        dp.minPrice = this.minPrice;
        dp.peakStarts = this.peakStarts;
        dp.peakEnds = this.peakEnds;
        dp.hasValues = this.hasValues;
        dp.endTime = this.endTime;
        dp.tradeCount = this.tradeCount;
        dp.tradeVolume = this.tradeVolume;
        dp.bestAsk = this.bestAsk;
        dp.bestBid = this.bestBid;
    }
}