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


import com.typesafe.config.Config;
import com.tzld.piaoquan.recommend.server.service.score4recall.AbstractScorer4Recall;
import com.tzld.piaoquan.recommend.server.service.score4recall.ScorerPipeline4Recall;
import com.tzld.piaoquan.recommend.server.util.FeatureBucketUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


@Slf4j
public final class ScorerUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(ScorerUtils.class);

    private static final Map<String, ScorerPipeline> scorerPipelineCache = new ConcurrentHashMap<>();
    private static final Map<String, ScorerPipeline4Recall> scorerPipelineCache4Recall = new ConcurrentHashMap<>();

    public static String BASE_CONF = "feeds_score_config_baseline.conf";
    public static String VIDEO_SCORE_CONF_FOR_AD = "video_score_config_for_ad.conf";

    public static String FLOWPOOL_CONF = "feeds_score_config_thompson.conf";


    public static void warmUp() {
        log.info("scorer warm up ");
        ScorerUtils.init(BASE_CONF);
        ScorerUtils.init(FLOWPOOL_CONF);
        ScorerUtils.init(VIDEO_SCORE_CONF_FOR_AD);
        ScorerUtils.init("feeds_score_config_20240228.conf");
        ScorerUtils.init("feeds_score_config_20240609.conf");
        ScorerUtils.init("feeds_score_config_20240711.conf");
        ScorerUtils.init("feeds_score_config_20240806.conf");
        ScorerUtils.init("feeds_score_config_20240807.conf");
        ScorerUtils.init("feeds_score_config_20241107.conf");
        ScorerUtils.init("feeds_score_config_20241119.conf");
        ScorerUtils.init("feeds_score_config_xgb_20240828.conf");
        ScorerUtils.init("feeds_score_config_fm_xgb_20241209.conf");
        ScorerUtils.init4Recall("feeds_recall_config_region_v1.conf");
        ScorerUtils.init4Recall("feeds_recall_config_region_v1_vov.conf");
        ScorerUtils.init4Recall("feeds_recall_config_region_v2.conf");
        ScorerUtils.init4Recall("feeds_recall_config_region_v3.conf");
        ScorerUtils.init4Recall("feeds_recall_config_region_v4.conf");
        ScorerUtils.init4Recall("feeds_recall_config_region_v5_highvalue.conf");
        ScorerUtils.init4Recall("feeds_recall_config_region_v6_rootrov.conf");
        ScorerUtils.init4Recall("feeds_recall_config_region_v7_vov_longterm.conf");
        ScorerUtils.init4Recall("feeds_score_config_festival.conf");
        ScorerUtils.init4Recall("feeds_score_config_bless.conf");
        ScorerUtils.init4Recall("feeds_recall_config_tomson.conf");
        ScorerUtils.init4Recall("feeds_recall_config_tomson_v2.conf");
        ScorerUtils.init4Recall("feeds_score_config_share_width.conf");
        ScorerUtils.init4Recall("feeds_score_config_share_deep.conf");
        ScorerUtils.init4Recall("content_base_recall.conf");
        FeatureBucketUtils.init(Collections.singletonList("20241209_nor_bucket.txt"));
    }

    private ScorerUtils() {
        // init(BASE_CONF);
    }

    public static void init(String configFile) {
        ScorerConfig scorerConfig = new ScorerConfig();
        scorerConfig.load(configFile);
        List<AbstractScorer> scorers = ScorerUtils.constructScorers(scorerConfig);

        initLoadModel(scorers);
        scorerPipelineCache.put(configFile, new ScorerPipeline(scorers));
    }

    public static void init4Recall(String configFile) {
        ScorerConfig scorerConfig = new ScorerConfig();
        scorerConfig.load(configFile);
        List<AbstractScorer4Recall> scorers = ScorerUtils.constructScorers4Recall(scorerConfig);

        initLoadModel4Recall(scorers);
        scorerPipelineCache4Recall.put(configFile, new ScorerPipeline4Recall(scorers));
    }

    /**
     * init load model
     *
     * @param scorers
     */
    public static void initLoadModel(List<AbstractScorer> scorers) {
        for (AbstractScorer scorer : scorers) {
            if (scorer.isEnable()) {
                scorer.loadModel();
            }
        }
    }

    public static void initLoadModel4Recall(List<AbstractScorer4Recall> scorers) {
        for (AbstractScorer4Recall scorer : scorers) {
            if (scorer.isEnable()) {
                scorer.loadModel();
            }
        }
    }

    public static void initLoadModel(String configFile) {
        ScorerConfig scorerConfig = new ScorerConfig();
        scorerConfig.load(configFile);
        List<AbstractScorer> scorers = ScorerUtils.constructScorers(scorerConfig);
        initLoadModel(scorers);
    }


    public static void initLoadModel(Config config) {
        ScorerConfig scorerConfig = new ScorerConfig();
        scorerConfig.load(config);
        List<AbstractScorer> scorers = ScorerUtils.constructScorers(scorerConfig);
        initLoadModel(scorers);
    }

    public static ScorerPipeline getScorerPipeline(String configFile) {
        // 不需要保证严格意义的单例
        if (scorerPipelineCache.containsKey(configFile)) {
            return scorerPipelineCache.get(configFile);
        }
        ScorerConfig scorerConfig = new ScorerConfig();
        scorerConfig.load(configFile);
        List<AbstractScorer> scorers = ScorerUtils.constructScorers(scorerConfig);
        ScorerPipeline pipeline = new ScorerPipeline(scorers);
        scorerPipelineCache.put(configFile, pipeline);
        return pipeline;
    }

    public static ScorerPipeline4Recall getScorerPipeline4Recall(String configFile) {
        // 不需要保证严格意义的单例
        if (scorerPipelineCache4Recall.containsKey(configFile)) {
            return scorerPipelineCache4Recall.get(configFile);
        }
        ScorerConfig scorerConfig = new ScorerConfig();
        scorerConfig.load(configFile);
        List<AbstractScorer4Recall> scorers = ScorerUtils.constructScorers4Recall(scorerConfig);
        ScorerPipeline4Recall pipeline = new ScorerPipeline4Recall(scorers);
        scorerPipelineCache4Recall.put(configFile, pipeline);
        return pipeline;
    }

    public static ScorerPipeline getScorerPipeline(Config mergeConfig) {
        ScorerConfig scorerConfig = new ScorerConfig();
        scorerConfig.load(mergeConfig);
        List<AbstractScorer> scorers = ScorerUtils.constructScorers(scorerConfig);
        return new ScorerPipeline(scorers);
    }

    public static ScorerPipeline getScorerPipeline(Config baselineConfig, List<Config> configList) {
        ScorerConfig scorerConfig = new ScorerConfig();
        scorerConfig.load(baselineConfig, configList);
        List<AbstractScorer> scorers = ScorerUtils.constructScorers(scorerConfig);
        return new ScorerPipeline(scorers);
    }

    /**
     * construct scorers
     *
     * @param scorerConfig
     * @return
     */
    public static List<AbstractScorer> constructScorers(ScorerConfig scorerConfig) {

        List<AbstractScorer> scorers = new ArrayList<AbstractScorer>();
        for (ScorerConfigInfo configInfo : scorerConfig.getConfigInfoList()) {
            if (!configInfo.getDisableSwitch()) {
                try {
                    AbstractScorer scorer = (AbstractScorer) Class.forName(configInfo.getScorerName())
                            .getConstructor(ScorerConfigInfo.class)
                            .newInstance(configInfo);
                    scorers.add(scorer);
                    LOGGER.debug("construct score [{}]", configInfo.getScorerName());
                } catch (Exception e) {
                    LOGGER.error("instance scorer {} failed {}", configInfo.getScorerName(), ExceptionUtils.getFullStackTrace(e));
                }

            }
        }
        return scorers;
    }

    /**
     * construct scorers
     *
     * @param scorerConfig
     * @return
     */
    public static List<AbstractScorer4Recall> constructScorers4Recall(ScorerConfig scorerConfig) {

        List<AbstractScorer4Recall> scorers = new ArrayList<AbstractScorer4Recall>();
        for (ScorerConfigInfo configInfo : scorerConfig.getConfigInfoList()) {
            if (!configInfo.getDisableSwitch()) {
                try {
                    AbstractScorer4Recall scorer = (AbstractScorer4Recall) Class.forName(configInfo.getScorerName())
                            .getConstructor(ScorerConfigInfo.class)
                            .newInstance(configInfo);
                    scorers.add(scorer);
                    LOGGER.debug("construct score [{}]", configInfo.getScorerName());
                } catch (Exception e) {
                    LOGGER.error("instance scorer {} failed {}", configInfo.getScorerName(), ExceptionUtils.getFullStackTrace(e));
                }

            }
        }
        return scorers;
    }

    /**
     * construct scorers
     *
     * @param scorerConfig
     * @return
     */
    public static List<AbstractScorer> constructQueueScorers(ScorerConfig scorerConfig, String queueName) {

        List<AbstractScorer> scorers = new ArrayList<AbstractScorer>();
        for (ScorerConfigInfo configInfo : scorerConfig.getConfigInfoList()) {
            if (!configInfo.getDisableSwitch() && configInfo.isQueueEnable(queueName)) {
                try {
                    AbstractScorer scorer = (AbstractScorer) Class.forName(configInfo.getScorerName())
                            .getConstructor(ScorerConfigInfo.class)
                            .newInstance(configInfo);
                    scorers.add(scorer);
                    LOGGER.debug("construct queue scorer [{}] [{}]", queueName, configInfo.getScorerName());
                } catch (Exception e) {
                    LOGGER.error("instance scorer {} failed {}", configInfo.getScorerName(), ExceptionUtils.getFullStackTrace(e));
                }
            }
        }
        return scorers;
    }
}
