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 com.tzld.piaoquan.recommend.server.util.FestiveUtil;
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.Arrays;
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 VIDEO_SCORE_CONF_FOR_AD = "video_score_config_for_ad.conf";


    public static void warmUp() {
        log.info("scorer warm up ");
        ScorerUtils.init(VIDEO_SCORE_CONF_FOR_AD);
        // 排序配置
        // ScorerUtils.init("feeds_score_config_20240609.conf");
        // ScorerUtils.init("feeds_score_config_20240807.conf");
        ScorerUtils.init("feeds_score_config_str_and_ros_20260319.conf");
        ScorerUtils.init("feeds_score_config_fm_xgb_20250317.conf");
        ScorerUtils.init("feeds_score_config_fm_xgb_20250729.conf");
        ScorerUtils.init("feeds_score_config_fm_xgb_20260116.conf");
        ScorerUtils.init("feeds_score_config_fm_xgb_20260123.conf");
        ScorerUtils.init("feeds_score_config_xgb_ros_20250311.conf");

        // 召回配置
        ScorerUtils.init4Recall("feeds_recall_config_region_v1.conf");
        ScorerUtils.init4Recall("feeds_recall_config_region_ros.conf");
        ScorerUtils.init4Recall("feeds_score_config_bless.conf");
        ScorerUtils.init4Recall("feeds_recall_config_tomson.conf");
        ScorerUtils.init4Recall("feeds_recall_config_region_v7_longterm.conf");

        // 分桶文件
        List<String> bucketFileList = Arrays.asList("20250218_bucket_322.txt", "20250306_ros_bucket_229.txt");
        FeatureBucketUtils.init(bucketFileList);
        FestiveUtil.init();
    }

    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;
    }
}
