package top.baogutang.strategy.strategies;

import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.baogutang.strategy.alerts.AlertChannel;
import top.baogutang.strategy.commons.enums.Timeframe;
import top.baogutang.strategy.models.*;
import top.baogutang.strategy.services.IndicatorService;

import java.util.*;

@Slf4j
public class MultiSymbolStrategyEngine {

    private final MultiSymbolMarketDataHub hub;
    private final IndicatorService indicators;
    private final RiskManager riskManager;
    private final AlertChannel alertChannel;
    private final Map<String, List<Strategy>> strategiesBySymbol;
    private final double baseEquity;
    private final double baseRiskPercent;
    private final PortfolioRiskManager portfolioRisk;
    private final Map<String, Double> symbolRiskOverride;

    public MultiSymbolStrategyEngine(MultiSymbolMarketDataHub hub,
                                     IndicatorService indicators,
                                     RiskManager riskManager,
                                     AlertChannel alertChannel,
                                     Map<String, List<Strategy>> strategiesBySymbol,
                                     double baseEquity,
                                     double baseRiskPercent,
                                     PortfolioRiskManager portfolioRisk,
                                     Map<String, Double> symbolRiskOverride) {
        this.hub = hub;
        this.indicators = indicators;
        this.riskManager = riskManager;
        this.alertChannel = alertChannel;
        this.strategiesBySymbol = strategiesBySymbol;
        this.baseEquity = baseEquity;
        this.baseRiskPercent = baseRiskPercent;
        this.portfolioRisk = portfolioRisk;
        this.symbolRiskOverride = symbolRiskOverride;
    }

    public void onKline(String symbol, Timeframe tf) {
//        log.info("onKline {} {}", symbol, tf);
        List<Strategy> list = strategiesBySymbol.get(symbol);
        if (list == null) return;
        double riskPercent = symbolRiskOverride.getOrDefault(symbol, baseRiskPercent);
        StrategyContext ctx = new StrategyContext(symbol, hub.raw(symbol), indicators, baseEquity, riskPercent, System.currentTimeMillis());
        for (Strategy s : list) {
            try {
                java.util.Optional<Signal> maybe = s.evaluate(ctx);
                if (maybe.isPresent()) {
                    Signal sig = maybe.get();
                    PositionPlan plan = riskManager.plan(baseEquity, riskPercent, sig.getEntryRef(), sig.getStopRef(), 0);
                    if (portfolioRisk != null) {
                        if (!portfolioRisk.canAccept(plan.getRiskAmount())) {
                            log.info("Portfolio risk reject {} {}", sig.getStrategy(), sig.getId());
                            continue;
                        }
                        portfolioRisk.register(sig.getId(), plan.getRiskAmount());
                    }
                    alertChannel.send(sig, plan);
                } else {
                    log.info("Strategy {} for coin:{} has no portfolio risk", s.name(), symbol);
                }
            } catch (Exception e) {
                log.error("Strategy {} error {}", s.name(), e.getMessage(), e);
            }
        }
    }
}
