import TradingPair from "../apiwrapper/assets/TradingPair.js";
import TradingPairs from "../apiwrapper/assets/TraidingPairs.js";
import APIEvent from "../apiwrapper/event/APIEvent.js";
import APIEventType from "../apiwrapper/event/APIEventType.js";
import KLineEvent from "../apiwrapper/event/KLineEvent.js";
import OrderBookUpdateEvent from "../apiwrapper/event/OrderBookUpdateEvent.js";
import Ticker24hEvent from "../apiwrapper/event/Ticker24hEvent.js";
import TradeEvent from "../apiwrapper/event/TradeEvent.js";
import Logger from "../logging/Logger.js";
import BotConfig from "./config/BotConfig.js";
import AssetData from "./data/asset/AssetData.js";

export default class AssetDataCollector {
    /**
     * @type{Map<string, AssetData}
     */
    #assetMap = new Map();

    /**
     * @type {Logger}
     */
    #logger = null;

    /**
     * @type {BotConfig}
     */
    #config = null;

    /**
     * @param {Logger} logger 
     * @param {BotConfig} config 
     */
    constructor(logger, config) {
        this.#logger = logger;
        this.#config = config;
    }

    init() {
        // TODO eventually load saved data
    }

    /**
     * 
     * @param {APIEvent} event 
     */
    pushAssetEvent(event) {
        switch (event.eventType) {
            case APIEventType.KLINE:
                this.pushKLine(event);
                break;
            case APIEventType.ORDER_BOOK_UPDATE:
                this.pushOrderBookUpdate(event);
                break;
            case APIEventType.TICKER_24H:
                this.push24hTicker(event);
                break;
            case APIEventType.TRADE:
                this.pushTrade(event);
                break;
            default:
                this.#logger.warn("Unknown event passed to AssetDataCollector!", event);
        }
    }

    /**
     * @param {TradingPair | string} tradingPair 
     * @returns {AssetData}
     */
    getAssetData(tradingPair){
        const symbol = tradingPair instanceof TradingPair ? tradingPair.getKey() : tradingPair;
        const tp = tradingPair instanceof TradingPair ? tradingPair : TradingPairs.fromString(symbol);

        if(!this.#assetMap.has(tp.getKey())){
            this.#assetMap.set(tp.getKey(), new AssetData(tp, this.#config.getDataCollectionConfig()));
        }

        return this.#assetMap.get(tp.getKey());
    }

    /**
     * @returns {TradingPair[]}
     */
    getManagedAssets(){
        return Array.from(this.#assetMap.values()).map(assetData => assetData.getTradingPair());
    }


    /**
     * Notify this data collector aboaut a trade
     * 
     * @param {TradeEvent} trade 
     */
    pushTrade(trade) {
        this.getAssetData(trade.tradingPair).pushTrade(trade.timestamp, trade.price, trade.quantity);
    }

    /**
     * Notify this data collector aboaut a kline
     * 
     * @param {KLineEvent} kline 
     */
    pushKLine(kline) {
        this.getAssetData(kline.tradingPair).updateKline(kline);
    }

    /**
     * Notify this data collector aboaut the 24h ticker
     * 
     * @param {Ticker24hEvent} ticker 
     */
    push24hTicker(ticker) {
        this.getAssetData(ticker.tradingPair).update24hData(ticker);
    }

    /**
     * Notify this data collector aboaut a order book update
     * 
     * @param {OrderBookUpdateEvent} orderBookUpdate 
     */
    pushOrderBookUpdate(orderBookUpdate) {
        this.getAssetData(orderBookUpdate.tradingPair).updateOrderBook(orderBookUpdate);
    }
}