package com.tzld.piaoquan.recommend.server.framework.userattention;

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.List;


public class UserAttentionExtractorUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserAttentionExtractorUtils.class);

    public static final String BASE_CONF = "";

    /**
     * 主调用函数
     *
     * @param config
     */
    public static void initLoadModel(Config config) {
        initLoadModel(constructExtractorList(constructExtractorConfigList(config)));
    }


    public static UserAttentionExtractorPipeline getAtttentionPipeline(String configFile) {

        Config attentionConfig = ConfigFactory.parseResources(configFile);
        List<AbstractUserAttentionExtractor> attentionExtractors = constructExtractorList(constructExtractorConfigList(attentionConfig));
        UserAttentionExtractorPipeline pipeline = new UserAttentionExtractorPipeline(attentionExtractors);

        return pipeline;
    }


    public static List<UserAttentionExtractorConfig> constructExtractorConfigList(Config config) {
        long startTime = System.currentTimeMillis();
        List<UserAttentionExtractorConfig> configList = new ArrayList<UserAttentionExtractorConfig>();
        try {
            Config mergedConfig = config.getConfig("attention-extractor-config");
            for (ConfigObject.Entry<String, ConfigValue> it : mergedConfig.root().entrySet()) {
                LOGGER.debug("deal with base config, attention key: [{}]", it.getKey());
                Config entryConf = ((ConfigObject) it.getValue()).toConfig();
                UserAttentionExtractorConfig extractorConfig = parseExtractorConfig(entryConf);
                addConfigByPriority(configList, extractorConfig);
            }
            // debug log
            if (LOGGER.isDebugEnabled()) {
                for (UserAttentionExtractorConfig extractorConfig : configList) {
                    LOGGER.debug("attention extractor config [{}] [{}]", extractorConfig.getName(), extractorConfig);
                }
            }
        } catch (Exception e) {
            LOGGER.error("construct extractor config {} failed {}", config.toString(), ExceptionUtils.getFullStackTrace(e));
        }
        return configList;
    }


    private static List<AbstractUserAttentionExtractor> constructExtractorList(List<UserAttentionExtractorConfig> configList) {
        long startTime = System.currentTimeMillis();
        List<AbstractUserAttentionExtractor> extractorList = new ArrayList<AbstractUserAttentionExtractor>();
        for (UserAttentionExtractorConfig config : configList) {
            try {
                AbstractUserAttentionExtractor extractor = (AbstractUserAttentionExtractor) Class.forName(config.getName())
                        .getConstructor(UserAttentionExtractorConfig.class)
                        .newInstance(config);
                extractorList.add(extractor);
            } catch (Exception e) {
                LOGGER.error("instance extractor {} failed {}", config.getName(), ExceptionUtils.getFullStackTrace(e));
            }
        }
        return extractorList;
    }

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

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

    private static int loadOptionIntConfig(Config config, String path) {
        return config.hasPath(path) ? config.getInt(path) : 0;
    }

    /**
     * attention层的配置化参数
     */
    private static UserAttentionExtractorConfig parseExtractorConfig(Config extractorConfig) {
        String attentionExtractorName = extractorConfig.getString("name");
        Integer priority = loadOptionIntConfig(extractorConfig, "attention-priority");
        Config paramConfig = loadOptionConfig(extractorConfig, "param-config");
        String modelPath = loadOptionStringConfig(extractorConfig, "model-path");
        return new UserAttentionExtractorConfig(attentionExtractorName,
                paramConfig,
                priority,
                modelPath);
    }


    /**
     * attention支持模型获取
     *
     * @param attentionExtractors
     */
    private static void initLoadModel(List<AbstractUserAttentionExtractor> attentionExtractors) {
        for (AbstractUserAttentionExtractor attentionExtractor : attentionExtractors) {
            attentionExtractor.loadModel();
        }
    }

    /**
     * 按优先级处理逻辑
     *
     * @param configInfoList
     * @param extractorConfig
     */
    private static void addConfigByPriority(List<UserAttentionExtractorConfig> configInfoList, UserAttentionExtractorConfig extractorConfig) {
        int pos = 0;
        for (; pos < configInfoList.size(); pos++) {
            if (configInfoList.get(pos).getPriority() <= extractorConfig.getPriority()) {
                break;
            }
        }
        configInfoList.add(pos, extractorConfig);
    }
}
