package top.baogutang.strategy;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import top.baogutang.strategy.alerts.AlertChannel;
import top.baogutang.strategy.alerts.CompositeAlertChannel;
import top.baogutang.strategy.alerts.ConsoleAlertChannel;
import top.baogutang.strategy.alerts.DingTalkRobotChannel;
import top.baogutang.strategy.commons.configs.AppProperties;
import top.baogutang.strategy.infra.OkxPublicClient;
import top.baogutang.strategy.infra.OkxWebSocketClient;
import top.baogutang.strategy.models.MultiSymbolMarketDataHub;
import top.baogutang.strategy.models.PortfolioRiskManager;
import top.baogutang.strategy.models.RiskManager;
import top.baogutang.strategy.services.IndicatorService;
import top.baogutang.strategy.strategies.MultiSymbolStrategyEngine;
import top.baogutang.strategy.strategies.Strategy;
import top.baogutang.strategy.strategies.StrategyFactory;

import java.util.*;

@Slf4j
@SpringBootApplication
public class AppApplication {

    public static void main(String[] args) {
        SpringApplication.run(AppApplication.class, args);
        log.info("<<<<<<<<<<baogutang strategy started>>>>>>>>>>");
    }

    @Bean
    public OkHttpClient okHttpClient() {
        return new OkHttpClient();
    }

    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper();
    }

    @Bean
    public IndicatorService indicatorService() {
        return new IndicatorService();
    }

    @Bean
    public MultiSymbolMarketDataHub multiSymbolMarketDataHub() {
        return new MultiSymbolMarketDataHub(800);
    }

    @Bean
    public OkxPublicClient okxPublicClient(OkHttpClient c, ObjectMapper m) {
        return new OkxPublicClient(c, m);
    }

    @Bean
    public OkxWebSocketClient okxWebSocketClient(OkHttpClient c, ObjectMapper m) {
        return new OkxWebSocketClient(c, m);
    }

    @Bean
    public RiskManager riskManager() {
        return new RiskManager(3.0);
    }

    @Bean
    public PortfolioRiskManager portfolioRiskManager(AppProperties props) {
        double p = props.getAccount().getPortfolioMaxOpenRiskPercent();
        if (p <= 0) return null;
        return new PortfolioRiskManager(props.getAccount().getEquity(), p);
    }

    @Bean
    public Map<String, List<Strategy>> strategies(AppProperties props) {
        return StrategyFactory.build(props);
    }

    @Bean
    public Map<String, Double> symbolRiskOverride(AppProperties props) {
        Map<String, Double> map = new HashMap<String, Double>();
        for (AppProperties.SymbolConfig sc : props.getSymbols()) {
            if (sc.getRiskPercentOverride() != null) {
                map.put(sc.getInstId(), sc.getRiskPercentOverride());
            }
        }
        return map;
    }

    @Bean
    public AlertChannel alertChannel(OkHttpClient http, ObjectMapper mapper, AppProperties props) {
        List<AlertChannel> list = new ArrayList<AlertChannel>();
        list.add(new ConsoleAlertChannel());
        if (props.getAlert() != null && props.getAlert().getDingTalk() != null) {
            List<AppProperties.Alert.DingTalkRobot> robots = props.getAlert().getDingTalk().getRobots();
            if (robots != null && !robots.isEmpty()) {
                List<DingTalkRobotChannel.RobotConfig> rcList = new ArrayList<DingTalkRobotChannel.RobotConfig>();
                for (AppProperties.Alert.DingTalkRobot r : robots) {
                    DingTalkRobotChannel.RobotConfig rc = new DingTalkRobotChannel.RobotConfig();
                    rc.name = r.getName();
                    rc.webhook = r.getWebhook();
                    rc.signEnable = r.getSecurity() != null && r.getSecurity().isEnable();
                    rc.secret = r.getSecurity() != null ? r.getSecurity().getSecret() : null;
                    rc.atMobiles = r.getAtMobiles();
                    rc.atAll = r.isAtAll();
                    rcList.add(rc);
                }
                list.add(new DingTalkRobotChannel(http, mapper, rcList));
            }
        }
        return new CompositeAlertChannel(list);
    }

    @Bean
    public MultiSymbolStrategyEngine multiSymbolStrategyEngine(MultiSymbolMarketDataHub hub,
                                                               IndicatorService ind,
                                                               RiskManager riskManager,
                                                               AlertChannel alertChannel,
                                                               Map<String, List<Strategy>> strategies,
                                                               AppProperties props,
                                                               PortfolioRiskManager portfolioRisk,
                                                               Map<String, Double> symbolRiskOverride) {
        return new MultiSymbolStrategyEngine(
                hub, ind, riskManager, alertChannel, strategies,
                props.getAccount().getEquity(), props.getAccount().getRiskPercent(),
                portfolioRisk, symbolRiskOverride);
    }
}
