package com.tzld.piaoquan.ad.engine.service.score.strategy;

import com.alibaba.fastjson.JSONObject;
import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
import com.tzld.piaoquan.ad.engine.commons.dto.AdPlatformCreativeDTO;
import com.tzld.piaoquan.ad.engine.commons.util.DateUtils;
import com.tzld.piaoquan.ad.engine.service.entity.GuaranteeView;
import com.tzld.piaoquan.ad.engine.commons.enums.RedisPrefixEnum;
import com.tzld.piaoquan.ad.engine.commons.param.RankRecommendRequestParam;
import com.tzld.piaoquan.ad.engine.commons.redis.AdRedisHelper;
import com.tzld.piaoquan.ad.engine.commons.score.ScoreParam;
import com.tzld.piaoquan.ad.engine.service.feature.Feature;
import com.tzld.piaoquan.ad.engine.service.feature.FeatureService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public abstract class RankStrategyBasic implements RankStrategy {

    @ApolloJsonValue("${no.postback.conversion.adverids:[]}")
    private Set<String> noPostbackConversionAdVerIds;

    @ApolloJsonValue("${creative.model.score.coefficient:{}}")
    private Map<Long, Double> creativeScoreCoefficient;

    @Value("${guarantee.exp:742}")
    protected String guaranteeExp;
    @ApolloJsonValue("${alpha:1.0}")
    protected Double alpha;
    @Autowired
    private FeatureService featureService;
    @Autowired
    protected AdRedisHelper adRedisHelper;

    String adPlatformGuaranteeKey = "ad:platform:guarantee:data:{date}:{adverId}";

    protected static final List<String> hasChannelScenes = new ArrayList<String>() {{
        add("DaiTou");
        add("GzhTouLiu");
        add("daitou");
        add("dyyjs");
        add("dyyqw");
        add("fwhdyy");
        add("gzhhz");
        add("gzhhzzx");
        add("shequn");
        add("touliu");
        add("xcxdt");
    }};


    protected Feature getFeature(ScoreParam param, RankRecommendRequestParam request) {
        List<AdPlatformCreativeDTO> adIdList = request.getAdIdList();
        List<String> cidList = adIdList.stream()
                .map(AdPlatformCreativeDTO::getCreativeId)
                .map(Object::toString)
                .collect(Collectors.toList());

        List<String> adVerIdList = adIdList.stream()
                .map(AdPlatformCreativeDTO::getAdVerId)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());

        List<Long> skuIdList = adIdList.stream()
                .map(AdPlatformCreativeDTO::getSkuId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        return featureService.getFeature(cidList, adVerIdList, skuIdList, param);
    }

    protected Set<String> getNoApiAdVerIds() {
        Set<String> noApiAdVerIds = adRedisHelper.sMembers(RedisPrefixEnum.ADVER_IS_API_EQ_0_IDS.getPrefix());
        log.info("Redis中缓存的没有回传广告主ID集合: {}", noApiAdVerIds);
        if (CollectionUtils.isEmpty(noApiAdVerIds)) {
            noApiAdVerIds = noPostbackConversionAdVerIds;
        }
        return noApiAdVerIds;
    }

    protected Map<Long, Double> getCreativeScoreCoefficient() {
        if (Objects.isNull(creativeScoreCoefficient)) {
            return new HashMap<>();
        }
        return creativeScoreCoefficient;
    }

    protected Map<String, String> getReqFeature(ScoreParam scoreParam, RankRecommendRequestParam request) {
        Map<String, String> map = new HashMap<>();
        map.put("brand", scoreParam.getRequestContext().getMachineinfoBrand().equalsIgnoreCase("-1") ?
                "" : scoreParam.getRequestContext().getMachineinfoBrand().toUpperCase());
        map.put("region", Objects.equals(scoreParam.getRequestContext().getRegion(), "-1") ?
                "" : scoreParam.getRequestContext().getRegion());
        map.put("city", Objects.equals(scoreParam.getRequestContext().getCity(), "-1") ?
                "" : scoreParam.getRequestContext().getCity());
        map.put("vid", String.valueOf(request.getVideoId()));
        map.put("apptype", String.valueOf(request.getAppType()));
        String rootSessionId = request.getRootSessionId();
        String sessionId = request.getSessionId();
        String subSessionId = request.getSubSessionId();
        String rootSourceId = request.getRootSourceId();
        int isFirstLayer;
        if (Objects.equals(rootSessionId, subSessionId) || Objects.equals(rootSessionId, sessionId)) {
            isFirstLayer = 1;
        } else {
            isFirstLayer = 2;
        }
        map.put("is_first_layer", String.valueOf(isFirstLayer));
        if (StringUtils.isNotEmpty(rootSourceId)) {
            String rootSourceScene = rootSourceId.split("_")[0];
            map.put("root_source_scene", rootSourceScene);
            if (hasChannelScenes.contains(rootSourceScene) && rootSourceId.split("_").length > 1) {
                String rootSourceChannel = rootSourceId.split("_")[1];
                map.put("root_source_channel", rootSourceChannel);
            }
        }
        return map;
    }

    protected Map<String, String> handleSceneFeature(long ts) {
        Map<String, String> sceneFeatureMap = new HashMap<>();
        sceneFeatureMap.put("hour_" + DateUtils.getHourByTimestamp(ts), "0.1");
        sceneFeatureMap.put("dayofweek_" + DateUtils.getDayOrWeekByTimestamp(ts), "0.1");
        sceneFeatureMap.put("hour", String.valueOf(DateUtils.getHourByTimestamp(ts)));
        sceneFeatureMap.put("hour_quarter", String.valueOf(DateUtils.getHourQuarter(ts)));
        sceneFeatureMap.put("ts", String.valueOf(ts));
        return sceneFeatureMap;
    }


    protected static class Tuple5 {
        public String f1;
        public String f2;
        public String f3;
        public String f4;
        public String f5;

        public Tuple5(String f1, String f2, String f3, String f4, String f5) {
            this.f1 = f1;
            this.f2 = f2;
            this.f3 = f3;
            this.f4 = f4;
            this.f5 = f5;
        }
    }

    protected static class TupleMapEntry<T> {
        public String key;
        public T value;

        public TupleMapEntry(String key, T value) {
            this.key = key;
            this.value = value;
        }
    }

    protected static class Tuple2<F1, F2> {
        public F1 f1;

        public F2 f2;

        public Tuple2(F1 first, F2 name) {
            this.f1 = first;
            this.f2 = name;
        }

    }

    protected Map<String, GuaranteeView> getGuaranteeViewMap(RankRecommendRequestParam request, ScoreParam scoreParam) {
        Map<String, GuaranteeView> map = new HashMap<>();
        try {
            if (scoreParam.getExpCodeSet().contains(guaranteeExp)) {
                String thatDayDateString = DateUtils.getThatDayDateString();
                String redisKey = adPlatformGuaranteeKey.replace("{date}", thatDayDateString);
                List<String> adVerIds = request.getAdIdList().stream().map(AdPlatformCreativeDTO::getAdVerId).distinct()
                        .filter(Objects::nonNull).collect(Collectors.toList());
                List<String> redisKeys = adVerIds.stream().map(e -> redisKey.replace("{adverId}", e)).collect(Collectors.toList());
                List<String> values = adRedisHelper.mget(redisKeys);
                if (CollectionUtils.isNotEmpty(values)) {
                    for (int i = 0; i < redisKeys.size(); i++) {
                        String value = values.get(i);
                        if (value != null) {
                            GuaranteeView guaranteeView = JSONObject.parseObject(value, GuaranteeView.class);
                            map.put(adVerIds.get(i), guaranteeView);
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("getGuaranteeViewMap error", e);
        }

        return map;
    }

    protected void setGuaranteeWeight(Map<String, GuaranteeView> map, String adVerId, Map<String, Object> ext) {
        if (MapUtils.isNotEmpty(map)) {
            GuaranteeView guaranteeView = map.get(adVerId);
            if (guaranteeView != null) {
                double guaranteeWeight = calculateGuaranteedWeight(guaranteeView);
                boolean isGuaranteed = isGuaranteed(guaranteeView);
                ext.put("guaranteeView", guaranteeView.toString());
                ext.put("guaranteeWeight", guaranteeWeight);
                ext.put("isGuaranteed", isGuaranteed);
            }
        }
    }

    protected double calculateGuaranteedWeight(GuaranteeView guaranteeView) {
        if (guaranteeView == null) {
            return 1.0;
        }
        double guaranteeWeight;
        if (guaranteeView.getGuaranteeNum() == null || guaranteeView.getGuaranteeNum() == 0
                || guaranteeView.getGuaranteeRate() == null || guaranteeView.getGuaranteeRate() == 0.0) {
            guaranteeWeight = 1.0;
        } else {
            if (guaranteeView.getAdrAlgoViewNum() != null &&
                    guaranteeView.getGuaranteeNum() <= guaranteeView.getAdrAlgoViewNum()) {
                guaranteeWeight = 0.0;
            } else {
                int allViewNum = guaranteeView.getAllAlgoViewNum() == null || guaranteeView.getAllAlgoViewNum() == 0 ?
                        1 : guaranteeView.getAllAlgoViewNum();
                int adrAlogViewNum = guaranteeView.getAdrAlgoViewNum() == null || guaranteeView.getAdrAlgoViewNum() == 0 ?
                        1 : guaranteeView.getAdrAlgoViewNum();
                //guaranteeView.getGuaranteeRate() 是百分之几  要乘0.01
                guaranteeWeight = guaranteeView.getGuaranteeRate() * 0.01 * allViewNum / adrAlogViewNum;
                if (guaranteeWeight < 0.5) {
                    guaranteeWeight = 0.5;
                }
                if (guaranteeWeight > 2) {
                    guaranteeWeight = 2;
                }
            }
        }
        return guaranteeWeight;
    }

    protected boolean isGuaranteed(GuaranteeView guaranteeView) {
        if (guaranteeView == null) {
            return false;
        }
        return guaranteeView.getGuaranteeNum() != null && guaranteeView.getGuaranteeNum() != 0
                && guaranteeView.getGuaranteeRate() != null && guaranteeView.getGuaranteeRate() != 0.0;
    }

    protected double getGuaranteeScoreCoefficient(ScoreParam scoreParam, Map<String, Object> ext) {
        if (scoreParam.getExpCodeSet().contains(guaranteeExp)) {
            if (ext.get("guaranteeWeight") == null) {
                return 1.0;
            } else {
                return Math.pow((double) ext.get("guaranteeWeight"), alpha);
            }
        } else {
            return 1.0;
        }
    }
}
