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

import com.alibaba.fastjson.JSON;
import com.aliyun.openservices.eas.predict.http.HttpConfig;
import com.aliyun.openservices.eas.predict.http.PredictClient;
import com.aliyun.openservices.eas.predict.request.TFDataType;
import com.aliyun.openservices.eas.predict.request.TFRequest;
import com.aliyun.openservices.eas.predict.response.TFResponse;
import com.tzld.piaoquan.recommend.feature.domain.ad.base.AdRankItem;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.*;


public class PAIModelV1 {

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

    private PAIModelV1() {
    }

    private static final PAIModelV1 model;

    public static PAIModelV1 getModel() {
        return model;
    }

    private static final PredictClient client;

    static {
        model = new PAIModelV1();
        client = new PredictClient(new HttpConfig());
        client.setEndpoint("1894469520484605.cn-hangzhou.pai-eas.aliyuncs.com");
        client.setToken("ODI1MmUxODgzZDc3ODM0ZmQwZWU0YTVjZjdlOWVlMGFlZGJjNTlkYQ==");
        client.setModelName("ad_rank_dnn_v11_easyrec");
    }

    private static final String[] sparseUserStrFeatures = {
            "brand", "region", "city", "cate1", "cate2", "user_cid_click_list", "user_cid_conver_list",
            "user_vid_return_tags_2h", "user_vid_return_tags_1d", "user_vid_return_tags_3d", "user_vid_return_tags_7d",
            "user_vid_return_tags_14d", "root_source_scene", "root_source_channel", "title_split", "user_vid_share_tags_1d",
            "user_vid_share_tags_14d", "user_vid_return_cate1_14d", "user_vid_return_cate2_14d", "user_vid_share_cate1_14d",
            "user_vid_share_cate2_14d"
    };

    private static final String[] sparseUserLongFeatures = {
            "vid", "apptype", "is_first_layer", "user_has_conver_1y"
    };

    private static final String[] sparseSceneLongFeatures = {
            "hour", "hour_quarter"
    };

    private static final String[] sparseAdLongFeatures = {
            "cid", "adid", "adverid",
            "user_adverid_view_3d", "user_adverid_view_7d", "user_adverid_view_30d",
            "user_adverid_click_3d", "user_adverid_click_7d", "user_adverid_click_30d",
            "user_adverid_conver_3d", "user_adverid_conver_7d", "user_adverid_conver_30d",
            "user_skuid_view_3d", "user_skuid_view_7d", "user_skuid_view_30d",
            "user_skuid_click_3d", "user_skuid_click_7d", "user_skuid_click_30d",
            "user_skuid_conver_3d", "user_skuid_conver_7d", "user_skuid_conver_30d"
    };

    private static final String[] sparseAdStrFeatures = {
            "profession"
    };

    private final String[] userFeatures = {
            "viewAll", "clickAll", "converAll", "incomeAll", "ctr_all", "ctcvr_all", "cvr_all", "ecpm_all"
    };

    private final String[] itemFeatures = {
            "actionstatic_click", "actionstatic_ctcvr", "actionstatic_ctr", "actionstatic_view", "b2_12h_click", "b2_12h_conver",
            "b2_12h_conver_x_ctcvr", "b2_12h_conver_x_log_view", "b2_12h_ctcvr", "b2_12h_ctr", "b2_12h_cvr", "b2_12h_ecpm",
            "b2_1d_click", "b2_1d_conver", "b2_1d_conver_x_ctcvr", "b2_1d_conver_x_log_view", "b2_1d_ctcvr", "b2_1d_ctr",
            "b2_1d_cvr", "b2_1d_ecpm", "b2_3d_click", "b2_3d_conver", "b2_3d_conver_x_ctcvr", "b2_3d_conver_x_log_view",
            "b2_3d_ctcvr", "b2_3d_ctr", "b2_3d_cvr", "b2_3d_ecpm", "b2_3h_click", "b2_3h_conver", "b2_3h_conver_x_ctcvr",
            "b2_3h_conver_x_log_view", "b2_3h_ctcvr", "b2_3h_ctr", "b2_3h_cvr", "b2_3h_ecpm", "b2_6h_click", "b2_6h_conver",
            "b2_6h_conver_x_ctcvr", "b2_6h_conver_x_log_view", "b2_6h_ctcvr", "b2_6h_ctr", "b2_6h_cvr", "b2_6h_ecpm", "b2_7d_click",
            "b2_7d_conver", "b2_7d_conver_x_ctcvr", "b2_7d_conver_x_log_view", "b2_7d_ctcvr", "b2_7d_ctr", "b2_7d_cvr",
            "b2_7d_ecpm", "b3_12h_click", "b3_12h_conver", "b3_12h_conver_x_ctcvr", "b3_12h_ctcvr", "b3_12h_ctr", "b3_12h_cvr",
            "b3_12h_ecpm", "b3_1d_click", "b3_1d_conver", "b3_1d_conver_x_ctcvr", "b3_1d_conver_x_log_view", "b3_1d_ctcvr",
            "b3_1d_ctr", "b3_1d_cvr", "b3_1d_ecpm", "b3_3d_click", "b3_3d_conver", "b3_3d_conver_x_ctcvr",
            "b3_3d_conver_x_log_view", "b3_3d_ctcvr", "b3_3d_ctr", "b3_3d_cvr", "b3_3d_ecpm", "b3_3h_click", "b3_3h_conver",
            "b3_3h_conver_x_ctcvr", "b3_3h_ctcvr", "b3_3h_ctr", "b3_3h_cvr", "b3_3h_ecpm", "b3_6h_click", "b3_6h_conver_x_ctcvr",
            "b3_6h_ctcvr", "b3_6h_ctr", "b3_6h_cvr", "b3_6h_ecpm", "b3_7d_click", "b3_7d_conver", "b3_7d_conver_x_ctcvr",
            "b3_7d_conver_x_log_view", "b3_7d_ctcvr", "b3_7d_ctr", "b3_7d_cvr", "b3_7d_ecpm", "b4_12h_click",
            "b4_12h_conver_x_ctcvr", "b4_12h_conver_x_log_view", "b4_12h_ctcvr", "b4_12h_ctr", "b4_12h_cvr", "b4_12h_ecpm",
            "b4_1d_click", "b4_1d_conver_x_ctcvr", "b4_1d_conver_x_log_view", "b4_1d_ctcvr", "b4_1d_ctr", "b4_1d_cvr", "b4_1d_ecpm",
            "b4_3d_click", "b4_3d_conver_x_ctcvr", "b4_3d_conver_x_log_view", "b4_3d_ctcvr", "b4_3d_ctr", "b4_3d_cvr", "b4_3d_ecpm",
            "b4_3h_click", "b4_3h_conver_x_ctcvr", "b4_3h_conver_x_log_view", "b4_3h_ctcvr", "b4_3h_ctr", "b4_3h_cvr", "b4_3h_ecpm",
            "b4_6h_click", "b4_6h_conver_x_ctcvr", "b4_6h_conver_x_log_view", "b4_6h_ctcvr", "b4_6h_ctr", "b4_6h_cvr", "b4_6h_ecpm",
            "b4_7d_click", "b4_7d_conver", "b4_7d_conver_x_ctcvr", "b4_7d_conver_x_log_view", "b4_7d_ctcvr", "b4_7d_ctr",
            "b4_7d_cvr", "b4_7d_ecpm", "b5_12h_click", "b5_12h_conver", "b5_12h_conver_x_ctcvr", "b5_12h_ctcvr", "b5_12h_ctr",
            "b5_12h_cvr", "b5_12h_ecpm", "b5_1d_click", "b5_1d_conver", "b5_1d_conver_x_ctcvr", "b5_1d_conver_x_log_view",
            "b5_1d_ctcvr", "b5_1d_ctr", "b5_1d_cvr", "b5_1d_ecpm", "b5_3d_click", "b5_3d_conver", "b5_3d_conver_x_ctcvr",
            "b5_3d_conver_x_log_view", "b5_3d_ctcvr", "b5_3d_ctr", "b5_3d_cvr", "b5_3d_ecpm", "b5_3h_click", "b5_3h_conver_x_ctcvr",
            "b5_3h_conver_x_log_view", "b5_3h_ctcvr", "b5_3h_ctr", "b5_3h_cvr", "b5_3h_ecpm", "b5_6h_click",
            "b5_6h_conver_x_log_view", "b5_6h_ctcvr", "b5_6h_ctr", "b5_6h_cvr", "b5_6h_ecpm", "b5_7d_click", "b5_7d_conver",
            "b5_7d_conver_x_ctcvr", "b5_7d_conver_x_log_view", "b5_7d_ctcvr", "b5_7d_ctr", "b5_7d_cvr", "b5_7d_ecpm", "b6_7d_click",
            "b6_7d_conver", "b6_7d_conver_x_log_view", "b6_7d_ctcvr", "b6_7d_ctr", "b6_7d_cvr", "b6_7d_ecpm", "b7_14d_ctr",
            "b7_7d_click", "b7_7d_conver_x_ctcvr", "b7_7d_conver_x_log_view", "b7_7d_ctcvr", "b7_7d_ctr", "b7_7d_cvr", "b7_7d_ecpm",
            "b8_12h_click", "b8_12h_conver_x_ctcvr", "b8_12h_ctcvr", "b8_12h_ctr", "b8_12h_cvr", "b8_12h_ecpm", "b8_1d_click",
            "b8_1d_conver", "b8_1d_conver_x_ctcvr", "b8_1d_conver_x_log_view", "b8_1d_ctcvr", "b8_1d_ctr", "b8_1d_cvr",
            "b8_1d_ecpm", "b8_3d_click", "b8_3d_conver", "b8_3d_conver_x_ctcvr", "b8_3d_ctcvr", "b8_3d_ctr", "b8_3d_cvr",
            "b8_3d_ecpm", "b8_3h_click", "b8_3h_conver_x_ctcvr", "b8_3h_ctcvr", "b8_3h_ctr", "b8_3h_cvr", "b8_3h_ecpm",
            "b8_6h_click", "b8_6h_conver_x_ctcvr", "b8_6h_ctcvr", "b8_6h_ctr", "b8_6h_cvr", "b8_6h_ecpm", "b8_7d_click",
            "b8_7d_conver_x_ctcvr", "b8_7d_conver_x_log_view", "b8_7d_ctcvr", "b8_7d_ctr", "b8_7d_cvr", "b8_7d_ecpm", "cpa",
            "d1_feature_12h_conver", "d1_feature_12h_ctcvr", "d1_feature_12h_ctr", "d1_feature_12h_cvr", "d1_feature_12h_ecpm",
            "d1_feature_1d_conver", "d1_feature_1d_ctcvr", "d1_feature_1d_ctr", "d1_feature_1d_cvr", "d1_feature_1d_ecpm",
            "d1_feature_3d_conver", "d1_feature_3d_ctcvr", "d1_feature_3d_ctr", "d1_feature_3d_ecpm", "d1_feature_3h_conver",
            "d1_feature_3h_ctcvr", "d1_feature_3h_ctr", "d1_feature_3h_cvr", "d1_feature_3h_ecpm", "d1_feature_6h_ctcvr",
            "d1_feature_6h_ctr", "d1_feature_6h_ecpm", "d1_feature_7d_conver", "d1_feature_7d_ctcvr", "d1_feature_7d_ctr",
            "d1_feature_7d_cvr", "d1_feature_7d_ecpm", "e1_tags_14d_avgscore", "e1_tags_14d_maxscore", "e1_tags_3d_avgscore",
            "e1_tags_3d_maxscore", "e1_tags_7d_avgscore", "e1_tags_7d_maxscore", "e2_tags_14d_avgscore", "e2_tags_14d_maxscore",
            "e2_tags_3d_avgscore", "e2_tags_3d_maxscore", "e2_tags_7d_avgscore", "e2_tags_7d_maxscore", "timediff_conver",
            "timediff_view", "vid_rank_ctcvr_14d", "vid_rank_ctcvr_1d", "vid_rank_ctcvr_3d", "vid_rank_ctcvr_7d",
            "vid_rank_ctr_14d", "vid_rank_ctr_1d", "vid_rank_ctr_3d", "vid_rank_ctr_7d", "vid_rank_ecpm_14d", "vid_rank_ecpm_1d",
            "vid_rank_ecpm_3d", "vid_rank_ecpm_7d"
    };


    public List<Float> score(final List<AdRankItem> items,
                             final Map<String, String> userFeatureMap,
                             final Map<String, String> sceneFeatureMap) {
        try {
            LOGGER.info("PAIModelV1 items={}", JSON.toJSONString(items.get(0).getFeatureMap()));
            TFRequest request = new TFRequest();

            for (String feature : sparseUserStrFeatures) {
                String v = userFeatureMap.getOrDefault(feature, "");
                request.addFeed(feature, TFDataType.DT_STRING, new long[]{1}, new String[]{v});
            }

            for (String feature : sparseUserLongFeatures) {
                long v = NumberUtils.toLong(userFeatureMap.getOrDefault(feature, "0"), 0);
                request.addFeed(feature, TFDataType.DT_INT64, new long[]{1}, new long[]{v});
            }

            for (String feature : sparseSceneLongFeatures) {
                long v = NumberUtils.toLong(sceneFeatureMap.getOrDefault(feature, "0"), 0);
                request.addFeed(feature, TFDataType.DT_INT64, new long[]{1}, new long[]{v});
            }


            for (String feature : userFeatures) {
                double v = NumberUtils.toDouble(userFeatureMap.getOrDefault(feature, "0.0"), 0.0);
                request.addFeed(feature.toLowerCase(), TFDataType.DT_DOUBLE, new long[]{1}, new double[]{v});
            }
            Map<String, double[]> doubleFeed = new HashMap<>();
            Map<String, long[]> longFeed = new HashMap<>();
            Map<String, String[]> strFeed = new HashMap<>();
            for (int i = 0; i < items.size(); i++) {
                for (String feature : itemFeatures) {
                    String key = feature.replace("_x_", "*").replace("_view", "(view)");
                    double[] doubles = doubleFeed.computeIfAbsent(feature, k -> new double[items.size()]);
                    if (MapUtils.isEmpty(items.get(i).getFeatureMap())) {
                        doubles[i] = 0.0;
                        continue;
                    }
                    double v = NumberUtils.toDouble(items.get(i).getFeatureMap().getOrDefault(key, "0.0"), 0.0);
                    doubles[i] = v;
                }

                for (String feature : sparseAdLongFeatures) {
                    long[] longs = longFeed.computeIfAbsent(feature, k -> new long[items.size()]);
                    if (MapUtils.isEmpty(items.get(i).getFeatureMap())) {
                        longs[i] = 0L;
                        continue;
                    }
                    long v = NumberUtils.toLong(items.get(i).getFeatureMap().getOrDefault(feature, "0"), 0L);
                    longs[i] = v;
                }

                for (String feature : sparseAdStrFeatures) {
                    String[] strs = strFeed.computeIfAbsent(feature, k -> new String[items.size()]);
                    if (MapUtils.isEmpty(items.get(i).getFeatureMap())) {
                        strs[i] = "";
                        continue;
                    }
                    String v = items.get(i).getFeatureMap().getOrDefault(feature, "");
                    strs[i] = v;
                }
            }
            for (Map.Entry<String, double[]> entry : doubleFeed.entrySet()) {
                request.addFeed(entry.getKey(), TFDataType.DT_DOUBLE, new long[]{items.size()}, entry.getValue());
            }

            for (Map.Entry<String, long[]> entry : longFeed.entrySet()) {
                request.addFeed(entry.getKey(), TFDataType.DT_INT64, new long[]{items.size()}, entry.getValue());
            }

            for (Map.Entry<String, String[]> entry : strFeed.entrySet()) {
                request.addFeed(entry.getKey(), TFDataType.DT_STRING, new long[]{items.size()}, entry.getValue());
            }
            request.addFetch("probs");
            LOGGER.info("PAIModelV1 request={}", request.getRequest().toString());
            TFResponse response = client.predict(request);
            List<Float> result = response.getFloatVals("probs");
            if (!CollectionUtils.isEmpty(result)) {
                LOGGER.info("PAIModelV1 result={}", result);
                return result;
            }
        } catch (Exception e) {
            LOGGER.error("PAIModel score error", e);
        }
        return new ArrayList<>(Collections.nCopies(items.size(), 0.0f));
    }

}
