package com.tzld.piaoquan.ad.engine.commons.score;


import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigObject;
import com.typesafe.config.ConfigValue;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class ScorerConfig {

    private static Logger LOGGER = LoggerFactory.getLogger(ScorerConfig.class);
    private List<ScorerConfigInfo> configInfoList = new ArrayList<ScorerConfigInfo>();

    public ScorerConfig(Config config) {
        this.load(config);
    }

    public ScorerConfig(String configFile) {
        this.load(configFile);
    }

    public ScorerConfig() {
    }

    public static Config mergeConfig(Config baselineConfig, List<Config> expConfigs) {
        if (expConfigs == null || expConfigs.size() == 0) {
            return baselineConfig;
        }
        Config resultConfig = expConfigs.get(0);
        for (Config config : expConfigs) {
            resultConfig = resultConfig.withFallback(config);
        }
        resultConfig = resultConfig.withFallback(baselineConfig);
        return resultConfig;
    }

    public boolean load(String configFile) {
        Config config = ConfigFactory.parseResources(configFile);
        return load(config);
    }

    public boolean load(Config baselineConfig, List<Config> expConfigs) {
        Config config = mergeConfig(baselineConfig, expConfigs);
        return load(config);
    }

    public boolean load(Config config) {
        Config scorerConfig = config.getConfig("scorer-config");

        try {
            loadScorers(scorerConfig);
            int pos = 0;
            for (ScorerConfigInfo scorerConfigInfo : configInfoList) {
                LOGGER.debug("scorer at position [{}], priority [{}], scorer name [{}]",
                        new Object[]{pos++, scorerConfigInfo.getScorerPriority(), scorerConfigInfo.getScorerName()});
            }
            LOGGER.debug("Load scorer config success");
        } catch (Exception e) {
            LOGGER.error("Load scorer config failed, [{}]", ExceptionUtils.getFullStackTrace(e));
            return false;
        }

        return true;
    }

    public List<ScorerConfigInfo> getConfigInfoList() {
        return configInfoList;
    }


    public String loadOptionStringConfig(Config config, String path) {
        return config.hasPath(path) ? config.getString(path) : null;
    }

    private Config loadOptionConfig(Config config, String path) {
        return config.hasPath(path) ? config.getConfig(path) : ConfigFactory.empty();
    }

    private void loadScorers(Config config) throws Exception {

        ConfigObject confObj = config.root();
        for (ConfigObject.Entry<String, ConfigValue> it : confObj.entrySet()) {
            Config conf = ((ConfigObject) it.getValue()).toConfig();
            // parse config
            String configName = it.getKey();
            String scorerName = conf.getString("scorer-name");
            int scorerPriority = 0;
            if (conf.hasPath("scorer-priority"))
                scorerPriority = conf.getInt("scorer-priority");
            Boolean disableSwitch = false;
            if (conf.hasPath("disable-switch")) {
                disableSwitch = conf.getBoolean("disable-switch");
            }
            Config paramConfig = loadOptionConfig(conf, "param-config");
            // model path
            String modelPath = loadOptionStringConfig(conf, "model-path");
            if (modelPath == null) {
                modelPath = loadOptionStringConfig(conf, "default-model-path");
                LOGGER.debug("model-path is not exists in config file, use default-model-path instead, modelPath={}", modelPath);
            }
            // enable queues
            Set<String> enableQueues = new HashSet<String>();
            if (conf.hasPath("enable-queues")) {
                enableQueues.addAll(conf.getStringList("enable-queues"));
            }
            ScorerConfigInfo configInfo = new ScorerConfigInfo(configName,
                    scorerName,
                    scorerPriority,
                    disableSwitch,
                    enableQueues,
                    modelPath,
                    paramConfig
            );
            LOGGER.debug("parse scorer config info [{}]", configInfo);
            // add to ConfigInfoList
            addConfigByPriority(configInfoList, configInfo);
        }
    }

    private void addConfigByPriority(List<ScorerConfigInfo> configInfoList, ScorerConfigInfo addConfigInfo) {

        int pos = 0;
        for (; pos < configInfoList.size(); pos++) {
            if (configInfoList.get(pos).getScorerPriority() <= addConfigInfo.getScorerPriority()) {
                break;
            }
        }

        configInfoList.add(pos, addConfigInfo);
    }
}
