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

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.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class PAIModelV3 {

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

    private PAIModelV3() {
    }

    private static final PAIModelV3 model;

    public static PAIModelV3 getModel() {
        return model;
    }

    private static final PredictClient client;

    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", "user_conver_ad_class", "user_layer"
    };

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

    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", "category_name", "customer", "landing",
    };

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

    /**
     * 预计算的 userFeatures 小写映射，避免运行时重复调用 toLowerCase()
     */
    private static final String[] userFeaturesLowerCase;

    private static 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",
            "j1_3d_conver_x_log_view", "j1_3d_conver", "j1_3d_ctcvr", "j1_3d_ctr",
            "j2_3d_conver_x_log_view", "j2_3d_conver", "j2_3d_ctcvr", "j2_3d_ctr",
            "j3_3h_conver_x_log_view", "j3_3h_conver", "j3_3h_ctcvr", "j3_3h_ctr", "j3_3d_conver_x_log_view", "j3_3d_conver", "j3_3d_ctcvr", "j3_3d_ctr",
            "j4_3d_conver_x_log_view", "j4_3d_conver", "j4_3d_ctcvr", "j4_3d_ctr",
            "j5_3d_conver_x_log_view", "j5_3d_conver", "j5_3d_ctcvr", "j5_3d_ctr",
            "j6_1h_click", "j6_1h_conver", "j6_1h_conver_x_ctcvr", "j6_1h_conver_x_log_view", "j6_1h_ctcvr", "j6_1h_ctr", "j6_1h_cvr", "j6_1h_ecpm",
            "j6_2h_click", "j6_2h_conver", "j6_2h_conver_x_ctcvr", "j6_2h_conver_x_log_view", "j6_2h_ctcvr", "j6_2h_ctr", "j6_2h_cvr", "j6_2h_ecpm",
            "j6_3h_click", "j6_3h_conver", "j6_3h_conver_x_ctcvr", "j6_3h_conver_x_log_view", "j6_3h_ctcvr", "j6_3h_ctr", "j6_3h_cvr", "j6_3h_ecpm",
            "j6_6h_ctr", "j6_6h_ecpm",
            "j6_12h_click", "j6_12h_conver", "j6_12h_conver_x_ctcvr", "j6_12h_conver_x_log_view", "j6_12h_ctcvr", "j6_12h_ctr", "j6_12h_cvr", "j6_12h_ecpm",
            "j6_3d_click", "j6_3d_conver", "j6_3d_conver_x_ctcvr", "j6_3d_conver_x_log_view", "j6_3d_ctcvr", "j6_3d_ctr", "j6_3d_cvr", "j6_3d_ecpm",
            "j7_3d_conver_x_log_view", "j7_3d_conver", "j7_3d_ctcvr", "j7_3d_ctr",
            "j8_3d_conver_x_log_view", "j8_3d_conver", "j8_3d_ctcvr", "j8_3d_ctr",
            "j9_3d_conver_x_log_view", "j9_3d_conver", "j9_3d_ctcvr", "j9_3d_ctr", "j9_3h_conver_x_log_view", "j9_3h_conver", "j9_3h_ctcvr", "j9_3h_ctr",
            "j10_3d_conver_x_log_view", "j10_3d_conver", "j10_3d_ctcvr", "j10_3d_ctr",
            "j11_3d_conver_x_log_view", "j11_3d_conver", "j11_3d_ctcvr", "j11_3d_ctr"
    };

    /**
     * 预计算的 itemFeatures key 映射，避免运行时重复执行 replace 操作
     * key: feature name, value: 转换后的 key（用于从 featureMap 中获取值）
     */
    private static final String[] itemFeatureKeys;

    static {
        model = new PAIModelV3();
        client = new PredictClient(new HttpConfig());
        client.setEndpoint("1894469520484605.vpc.cn-hangzhou.pai-eas.aliyuncs.com");
        client.setToken("YzNmYjZiZjk3NTQ5NGI0MmFmZTc3MjA5YTljZjJlN2VkYjI0MzQxYw==");
        client.setModelName("ad_rank_dnn_v11_easyrec_v4");


        // 预计算 itemFeatures 的 key 映射
        itemFeatureKeys = new String[itemFeatures.length];
        for (int i = 0; i < itemFeatures.length; i++) {
            itemFeatureKeys[i] = itemFeatures[i].replace("_x_", "*").replace("_view", "(view)");
        }

        // 预计算 userFeatures 的小写映射
        userFeaturesLowerCase = new String[userFeatures.length];
        for (int i = 0; i < userFeatures.length; i++) {
            userFeaturesLowerCase[i] = userFeatures[i].toLowerCase();
        }
    }


    public Map<String, List<Float>> score(final List<AdRankItem> items,
                                          final Map<String, String> userFeatureMap,
                                          final Map<String, String> sceneFeatureMap) {
        long totalStart = System.currentTimeMillis();
        long buildUserFeatureTime = 0;
        long buildItemFeatureTime = 0;
        long buildRequestTime = 0;
        long predictTime = 0;
        long parseResponseTime = 0;

        final int size = items.size();

        try {
            TFRequest request = new TFRequest();

            // 阶段1: 构建用户特征
            long stageStart = System.currentTimeMillis();
            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 (int i = 0; i < userFeatures.length; i++) {
                double v = NumberUtils.toDouble(userFeatureMap.getOrDefault(userFeatures[i], "0.0"), 0.0);
                request.addFeed(userFeaturesLowerCase[i], TFDataType.DT_DOUBLE, new long[]{1}, new double[]{v});
            }
            buildUserFeatureTime = System.currentTimeMillis() - stageStart;

            // 阶段2: 构建广告Item特征（优化版本）
            stageStart = System.currentTimeMillis();

            // 预提取所有 item 的 featureMap 引用，避免重复调用 get 方法
            Map[] featureMaps = new Map[size];
            for (int i = 0; i < size; i++) {
                featureMaps[i] = items.get(i).getFeatureMap();
            }

            // 预分配所有数组
            double[][] doubleArrays = new double[itemFeatures.length][size];
            long[][] longArrays = new long[sparseAdLongFeatures.length][size];
            String[][] strArrays = new String[sparseAdStrFeatures.length][size];

            // 按 feature 遍历（外层），提高缓存局部性
            // 处理 double 类型特征
            for (int f = 0; f < itemFeatures.length; f++) {
                String key = itemFeatureKeys[f];
                double[] doubles = doubleArrays[f];
                for (int i = 0; i < size; i++) {
                    Map<String, String> featureMap = featureMaps[i];
                    if (featureMap == null || featureMap.isEmpty()) {
                        doubles[i] = 0.0;
                    } else {
                        doubles[i] = NumberUtils.toDouble(featureMap.getOrDefault(key, "0.0"), 0.0);
                    }
                }
            }

            // 处理 long 类型特征
            for (int f = 0; f < sparseAdLongFeatures.length; f++) {
                String feature = sparseAdLongFeatures[f];
                long[] longs = longArrays[f];
                for (int i = 0; i < size; i++) {
                    Map<String, String> featureMap = featureMaps[i];
                    if (featureMap == null || featureMap.isEmpty()) {
                        longs[i] = 0L;
                    } else {
                        longs[i] = NumberUtils.toLong(featureMap.getOrDefault(feature, "0"), 0L);
                    }
                }
            }

            // 处理 String 类型特征
            for (int f = 0; f < sparseAdStrFeatures.length; f++) {
                String feature = sparseAdStrFeatures[f];
                String[] strs = strArrays[f];
                for (int i = 0; i < size; i++) {
                    Map<String, String> featureMap = featureMaps[i];
                    if (featureMap == null || featureMap.isEmpty()) {
                        strs[i] = "";
                    } else {
                        strs[i] = featureMap.getOrDefault(feature, "");
                    }
                }
            }
            buildItemFeatureTime = System.currentTimeMillis() - stageStart;

            // 阶段3: 构建请求体
            stageStart = System.currentTimeMillis();
            long[] shape = new long[]{size};

            for (int f = 0; f < itemFeatures.length; f++) {
                request.addFeed(itemFeatures[f], TFDataType.DT_DOUBLE, shape, doubleArrays[f]);
            }

            for (int f = 0; f < sparseAdLongFeatures.length; f++) {
                request.addFeed(sparseAdLongFeatures[f], TFDataType.DT_INT64, shape, longArrays[f]);
            }

            for (int f = 0; f < sparseAdStrFeatures.length; f++) {
                request.addFeed(sparseAdStrFeatures[f], TFDataType.DT_STRING, shape, strArrays[f]);
            }
            request.addFetch("probs");
            buildRequestTime = System.currentTimeMillis() - stageStart;

            // 阶段4: PAI-EAS 远程调用
            stageStart = System.currentTimeMillis();
            TFResponse response = client.predict(request);
            predictTime = System.currentTimeMillis() - stageStart;

            // 阶段5: 解析响应
            stageStart = System.currentTimeMillis();
            List<Float> scanResult = response.getFloatVals("probs_has_scan");
            List<Float> addWechatResult = response.getFloatVals("probs_has_addwechat");
            List<Float> conversionResult = response.getFloatVals("probs_has_conversion");
            parseResponseTime = System.currentTimeMillis() - stageStart;
            Map<String, List<Float>> result = new HashMap<>();
            result.put("scanResult", scanResult);
            result.put("addWechatResult", addWechatResult);
            result.put("conversionResult", conversionResult);
            return result;
        } catch (Exception e) {
            long totalTime = System.currentTimeMillis() - totalStart;
            LOGGER.error("PAIModelV3.score error: total={}ms, itemSize={}, buildUserFeature={}ms, " +
                            "buildItemFeature={}ms, buildRequest={}ms, predict={}ms, parseResponse={}ms",
                    totalTime, items.size(), buildUserFeatureTime, buildItemFeatureTime,
                    buildRequestTime, predictTime, parseResponseTime, e);
        }
        return new HashMap<>();
    }

}
