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

import com.tzld.piaoquan.ad.engine.commons.score.AdConfig;
import com.tzld.piaoquan.recommend.feature.domain.ad.base.AdActionFeature;
import com.tzld.piaoquan.recommend.feature.domain.ad.base.AdRankItem;
import com.tzld.piaoquan.recommend.feature.model.sample.BaseFeature;
import com.tzld.piaoquan.recommend.feature.model.sample.GroupedFeature;
import com.tzld.piaoquan.recommend.feature.model.sample.LRSamples;
import it.unimi.dsi.fastutil.longs.Long2FloatMap;
import it.unimi.dsi.fastutil.longs.Long2FloatOpenHashMap;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.math3.distribution.BetaDistribution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class ThompsonSamplingModel extends Model {
    protected static final int MODEL_FIRST_LOAD_COUNT = 1 << 25;  // 32M
    private static final Logger LOGGER = LoggerFactory.getLogger(ThompsonSamplingModel.class);

    // key = adid, value = <exp, click, conversation>
    private Map<Long, AdActionFeature> thompsonSamplingModel;

    private static final int alpha = 60;
    private static final int beta_click = 2000;
    private static final int beta_conversion = 2000;

    public ThompsonSamplingModel() {
        //配置不同环境的hdfs conf
        this.thompsonSamplingModel = new HashMap<>();
    }

    public Map<Long, AdActionFeature> getLrModel() {
        return this.thompsonSamplingModel;
    }


    public void putFeature(Map<Long, AdActionFeature> model, Long key, Double expose, Double click, Double conversation) {
        AdActionFeature adActionFeature = new AdActionFeature();
        adActionFeature.setAdView(expose);
        adActionFeature.setAdClick(click);
        adActionFeature.setAdConversion(conversation);
        model.put(key, adActionFeature);
    }


    @Override
    public boolean loadFromStream(InputStreamReader in) throws IOException {
        Map<Long, AdActionFeature> initModel = new HashMap<>();
        BufferedReader input = new BufferedReader(in);
        String line = null;
        int cnt = 0;
        List<Long> adIds = new ArrayList<>();
        while ((line = input.readLine()) != null) {
            String[] items = line.split("\t");
            if (items.length < 3) {
                continue;
            }
            adIds.add(NumberUtils.toLong(items[0].trim(), 0));
            putFeature(initModel, new BigInteger(items[0].trim()).longValue(), Double.valueOf(items[1].trim()).doubleValue(), Double.valueOf(items[2].trim()).doubleValue(), Double.valueOf(items[3].trim()).doubleValue());
        }
        // hardcode modelPath 不能重复，所以这里直接赋值
        AdConfig.setAdIds(adIds);

        this.thompsonSamplingModel = initModel;
        LOGGER.info("[MODELLOAD] model load over and size " + cnt);
        input.close();
        in.close();
        return true;
    }


    @Override
    public int getModelSize() {
        if (this.thompsonSamplingModel == null)
            return 0;
        int sum = this.thompsonSamplingModel.size();
        return sum;
    }

    public double score(AdRankItem adRankItem, String ctrOrCVR) {
        double score = 0.0f;
        AdActionFeature adActionFeature = this.thompsonSamplingModel.getOrDefault(adRankItem.getAdId(),new AdActionFeature());

        if (ctrOrCVR.equals("ctr")){
            int alpha_ctr = (int) adActionFeature.getAdClick() + this.alpha ;
            int beta_ctr = this.beta_click + (int)adActionFeature.getAdView() - (int)adActionFeature.getAdClick();
            score = this.betaSampler(alpha_ctr, beta_ctr);
        }
        if (ctrOrCVR.equals("cvr")){
            int alpha_cvr = (int) adActionFeature.getAdConversion() + this.alpha ;
            int beta_cvr = this.beta_conversion + (int)adActionFeature.getAdClick() - (int)adActionFeature.getAdConversion();
            score = this.betaSampler(alpha_cvr, beta_cvr);
        }
        return score;
    }

    public double betaSampler(double alpha, double beta) {
        BetaDistribution betaSample = new BetaDistribution(alpha, beta);
        return betaSample.sample();
    }


}
