import Transaction from "../../apiwrapper/transaction/Transaction.js";
import TransactionPhase from "../../apiwrapper/transaction/TransactionPhase.js";
import AbstractStrategy from "./AbstractStrategy.js";

export default class AvgEmaStrategy extends AbstractStrategy {
    #lastBuySuggestionTime = 0;
    #waitingMultiplier = 1;

    #buyRecomendationRequired = false;
    #sellRecomendationRequired = false;

    constructor(){
        super();
        this.#lastBuySuggestionTime = Date.now();
    }

    /**
     * @param {Transaction} transaction 
     * @returns {boolean}
     */
    shouldSell(transaction) {
        const winPercent = (this.getAssetData().getOrderBook().getBestBid().price * 100) / transaction.buySettings.price - 100;
        const elapsedTime = Date.now() - transaction.timestamp;

        if(!this.isAllowedToSell(transaction, winPercent)){
            return false;
        }

        if(elapsedTime < 600000){
            return true;
        }

        if(winPercent > 2.5){
            return true;
        }

        const aggDataPoints = this.getAssetData().getAggregatedData('15m');
        const price = this.getAssetData().getOrderBook().getBestBid().price;

        let isEmaHigher = false;
        for(let i = 10; i < aggDataPoints.length; i++){
            isEmaHigher |= aggDataPoints[i].ema15min > aggDataPoints[i].avgPrice;
        }

        if(isEmaHigher){
            this.#waitingMultiplier = 1;
            this.getLogger().event("[SELL][" + this.constructor.name + "] recomendet sell for " + transaction.id + " for " + price.toFixed(6));
            return true;
        }

        return false;
    }

    /**
     * @returns {boolean}
     */
    shouldBuy() {
        if(Date.now() < this.#lastBuySuggestionTime + (60000 * this.#waitingMultiplier)){
            return false;
        }

        this.#waitingMultiplier = 1;

        const aggDataPoints = this.getAssetData().getAggregatedData('15m');
        const aggDataPoints1h = this.getAssetData().getAggregatedData('1h', -1, true);

        if(aggDataPoints == null || aggDataPoints.length < 10 || aggDataPoints1h.length < 30){
            return false;
        }

        if(aggDataPoints1h[0].ema15min > aggDataPoints1h[aggDataPoints1h.length - 1].ema15min){
            return false;
        }
        
        const price = this.getAssetData().getOrderBook().getBestBid().price;
        const priceChange15Min = 100 - (aggDataPoints[aggDataPoints.length - 1].minPrice * 100) / aggDataPoints[0].maxPrice;

        let isEmaHigher = true;
        let wasEmaHigher = false;
        for(let i = 10; i < aggDataPoints.length; i++){
            if(!wasEmaHigher && aggDataPoints[i].ema15min > aggDataPoints[i].avgPrice){
                wasEmaHigher =true;
                continue;
            }
            if(wasEmaHigher && aggDataPoints[i].ema15min < aggDataPoints[i].avgPrice){
                isEmaHigher = false;
                break;
            }
        }

        if(priceChange15Min > 0.4 && !isEmaHigher){
            this.#lastBuySuggestionTime = Date.now();
            this.#waitingMultiplier = 15;
            this.getLogger().event("[BUY][" + this.constructor.name + "][" + this.getAssetData().getTradingPair().getKey() + "] recomendet buy for " + price.toFixed(6));
            return true;
        }

        return false;
    }

    /**
     * @param {Transaction} transaction 
     * @returns {boolean}
     */
    shouldCancle(transaction) {
        if(!this.isAllowedToCancel(transaction)){
            return false;
        }

        const price = this.getAssetData().getOrderBook().getBestBid().price;

        if(transaction.buySettings != null && transaction.phase == TransactionPhase.BUY_IN_PROGRESS){
            if(transaction.buySettings.orderPrice * 1.002 < price){
                this.getLogger().event("[CANCEL][" + this.constructor.name + "] recomendet cancel for " + transaction.id);
                return true;
            }
        }

        return false;
    }

    /**
    * @returns {string} string representation of this object
    */
    toJson() {
        const obj = JSON.parse(super.toJson());

        return JSON.stringify(obj);
    }

    /**
     * @param {string} objString 
     * @returns {AvgEmaStrategy}
     */
    static fromJson(objString) {
        return new AvgEmaStrategy();
    }
}