package com.tzld.piaoquan.recommend.server.service.rank;

import com.tzld.piaoquan.recommend.server.service.ExperimentService;
import com.tzld.piaoquan.recommend.server.service.ServiceBeanFactory;
import com.tzld.piaoquan.recommend.server.service.rank.strategy.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

@Service
@Slf4j
public class RankRouter {


    @Value("${rank.strategy.default:567}")
    private String rankStrategyDefault;

    @Resource
    private ExperimentService experimentService;

    private LinkedHashMap<String, RankService> strategyMap;

    private static final String relevantRank = "relevant";
    private static final Map<String, Class<? extends RankService>> STRATEGY_CLASSES = new HashMap<>();

    static {
        STRATEGY_CLASSES.put("536", RankStrategy4RegionMergeModelV536.class);
        STRATEGY_CLASSES.put("562", RankStrategy4RegionMergeModelV562.class);
        STRATEGY_CLASSES.put("563", RankStrategy4RegionMergeModelV563.class);
        STRATEGY_CLASSES.put("564", RankStrategy4RegionMergeModelV564.class);
        STRATEGY_CLASSES.put("565", RankStrategy4RegionMergeModelV565.class);
        STRATEGY_CLASSES.put("566", RankStrategy4RegionMergeModelV566.class);
        STRATEGY_CLASSES.put("567", RankStrategy4RegionMergeModelV567.class);
        STRATEGY_CLASSES.put("569", RankStrategy4RegionMergeModelV569.class);
        STRATEGY_CLASSES.put("568", RankStrategy4RegionMergeModelV568.class);
        STRATEGY_CLASSES.put("839", RankStrategy4RegionMergeModelV839.class);
        STRATEGY_CLASSES.put(relevantRank, RankStrategy4RelevantModelV1.class);
    }

    @Autowired
    public RankRouter(ServiceBeanFactory serviceBeanFactory) {
        this.strategyMap = new LinkedHashMap<>();
        for (Map.Entry<String, Class<? extends RankService>> entry : STRATEGY_CLASSES.entrySet()) {
            try {
                this.strategyMap.put(entry.getKey(), serviceBeanFactory.getBean(entry.getValue()));
            } catch (Exception e) {
                log.error("Failed to initialize strategy: {}", entry.getKey(), e);
            }
        }
    }

    public RankResult rank(RankParam param) {
        if (2 == param.getRecommendType() && strategyMap.containsKey(relevantRank)) {
            return strategyMap.get(relevantRank).rank(param);
        }

        // 裂变层实验，使用RootSessionId尾号进行实验
        for (Map.Entry<String, RankService> entry : strategyMap.entrySet()) {
            boolean hitExp = experimentService.judgeHitExp(param.getAppType(), param.getRootSessionId(), null, entry.getKey());
            if (hitExp) {
                // log.info("apType: {}, rootSessionId: {} 命中实验: {} strategies: {}", param.getAppType(), param.getRootSessionId(), entry.getKey(), entry.getValue().getClass().getSimpleName());
                return entry.getValue().rank(param);
            }
        }

        Set<String> abExpCodes = param.getAbExpCodes();
        if (CollectionUtils.isNotEmpty(abExpCodes)) {
            for (Map.Entry<String, RankService> entry : strategyMap.entrySet()) {
                if (abExpCodes.contains(entry.getKey())) {
                    // log.info("rank strategies {} {}", entry.getKey(), entry.getValue().getClass().getSimpleName());
                    return entry.getValue().rank(param);
                }
            }
        }

        if (null != rankStrategyDefault && strategyMap.containsKey(rankStrategyDefault)) {
            return strategyMap.get(rankStrategyDefault).rank(param);
        }

        Optional<RankService> defaultStrategy = strategyMap.values().stream().findFirst();
        if (defaultStrategy.isPresent()) {
            return defaultStrategy.get().rank(param);
        } else {
            log.error("No available rank strategy found.");
            return null;
        }
    }
}

