package com.duiba.tuia.youtui.web.service.impl;

import cn.com.duiba.goods.center.api.remoteservice.dto.item.ItemDto;
import cn.com.duiba.tuia.activity.center.api.constant.ActivityOptionType;
import cn.com.duiba.tuia.activity.center.api.constant.PluginType;
import cn.com.duiba.tuia.activity.center.api.constant.ResponsiveAppearType;
import cn.com.duiba.tuia.activity.center.api.constant.Scene;
import cn.com.duiba.tuia.activity.center.api.dto.ActivityOptionDto;
import cn.com.duiba.tuia.activity.center.api.dto.ActivityOrderDto;
import cn.com.duiba.tuia.activity.center.api.dto.ActivityPluginDto;
import cn.com.duiba.tuia.activity.center.api.dto.PeriodDto;
import cn.com.duiba.tuia.activity.center.api.dto.PluginSkinDto;
import cn.com.duiba.tuia.activity.center.api.dto.RspOrder;
import cn.com.duiba.tuia.activity.center.api.remoteservice.RemotePluginService;
import cn.com.duiba.tuia.activity.center.api.util.EntityUtil;
import cn.com.duiba.tuia.ssp.center.api.dto.PlugBuoyConfigDto;
import cn.com.duiba.tuia.ssp.center.api.dto.SlotDto;
import cn.com.duiba.wolf.dubbo.DubboResult;
import cn.com.duiba.wolf.utils.DateUtils;
import cn.com.duiba.wolf.utils.UrlUtils;
import cn.com.duibaboot.ext.autoconfigure.accesslog.AccessLogFilter;
import cn.com.tuia.advert.model.QueryAdvertRsp;
import com.alibaba.fastjson.JSONObject;
import com.dianping.cat.Cat;
import com.duiba.tuia.youtui.web.constant.AppIdConstant;
import com.duiba.tuia.youtui.web.constant.Constants;
import com.duiba.tuia.youtui.web.constant.CouponSource;
import com.duiba.tuia.youtui.web.constant.DmCookieHolder;
import com.duiba.tuia.youtui.web.constant.ErrorCode;
import com.duiba.tuia.youtui.web.constant.Tenter;
import com.duiba.tuia.youtui.web.embed.DcmBuilder;
import com.duiba.tuia.youtui.web.embed.DpmBuilder;
import com.duiba.tuia.youtui.web.embed.PluginEmbed;
import com.duiba.tuia.youtui.web.exception.ActivityException;
import com.duiba.tuia.youtui.web.exception.ActivityRuntimeException;
import com.duiba.tuia.youtui.web.exception.BusinessException;
import com.duiba.tuia.youtui.web.model.PluginTimeNum;
import com.duiba.tuia.youtui.web.model.ResponsiveJoinTimes;
import com.duiba.tuia.youtui.web.model.UserAccount;
import com.duiba.tuia.youtui.web.model.req.DoJoinActivityReq;
import com.duiba.tuia.youtui.web.model.req.PluginToolsReq;
import com.duiba.tuia.youtui.web.model.rsp.PluginToolsRsp;
import com.duiba.tuia.youtui.web.service.ActivityOrderService;
import com.duiba.tuia.youtui.web.service.ActivityService;
import com.duiba.tuia.youtui.web.service.BaseCacheService;
import com.duiba.tuia.youtui.web.service.CommonService;
import com.duiba.tuia.youtui.web.service.DirectPageSourceService;
import com.duiba.tuia.youtui.web.service.LuckBagService;
import com.duiba.tuia.youtui.web.service.PluginToolsService;
import com.duiba.tuia.youtui.web.service.SlotService;
import com.duiba.tuia.youtui.web.tool.CookieUtil;
import com.duiba.tuia.youtui.web.tool.DomainUtil;
import com.duiba.tuia.youtui.web.tool.DpmInfo;
import com.duiba.tuia.youtui.web.tool.EmbedUtil;
import com.duiba.tuia.youtui.web.tool.PathUtil;
import com.duiba.tuia.youtui.web.tool.RequestLocal;
import com.duiba.tuia.youtui.web.tool.StringTool;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;


/**
 * 插件工具service实现类
 *
 * @author chengdeman
 * @create 2017-05-12 下午4:47
 **/
@Service
public class PluginToolsServiceImpl extends BaseCacheService implements PluginToolsService, InitializingBean {


    /**
     * The activity service.
     */
    @Autowired
    private ActivityService activityService;

    /**
     * The activity order service.
     */
    @Autowired
    private ActivityOrderService activityOrderService;

    /**
     * The luck bag service.
     */
    @Autowired
    private LuckBagService luckBagService;


    @Autowired
    private CommonService commonService;

    /**
     * The activity order service.
     */
    @Autowired
    private RemotePluginService remotePluginService;

    @Resource
    private SlotService slotService;

    @Resource
    private DirectPageSourceService directPageSourceService;

    private static final String PLUGIN_INDEX_CAT = "活动中心-插件访问";

    private LoadingCache<String, List<ActivityPluginDto>> timingPluginCache;

    private LoadingCache<Long,ActivityPluginDto> pluginCache;

    private LoadingCache<String,List<ActivityPluginDto>> availableCommonPlugin;



    @Override
    public void afterPropertiesSet() {
        this.timingPluginCache = CacheBuilder
                .newBuilder()
                .maximumSize(10)
                .refreshAfterWrite(10, TimeUnit.SECONDS)//缓存10s刷新一次(load不到新数据时仍返回旧数据)
                .expireAfterWrite(10, TimeUnit.MINUTES)//缓存10分钟强制刷新一次
                .build(new CacheLoader<String, List<ActivityPluginDto>>() {

                    @Override
                    public List<ActivityPluginDto> load(String s) throws Exception {
                        return selectAvailablePluginByMinuteAndType(PluginType.TIMINGPLUGIN);
                    }
                });
        this.pluginCache = CacheBuilder
                .newBuilder()
                .maximumSize(100)
                .refreshAfterWrite(30, TimeUnit.SECONDS)
                .build(new CacheLoader<Long, ActivityPluginDto>() {
                    @Override
                    public ActivityPluginDto load(Long pluginId) {
                        ActivityPluginDto dto = remotePluginService.selectActivityPluginById(pluginId).getResult();
                        if (dto == null) {
                            dto = ActivityPluginDto.EMPTY_DTO;
                        }
                        return dto;
                    }
                });

        availableCommonPlugin = CacheBuilder
                .newBuilder()
                .maximumSize(10)
                .refreshAfterWrite(30, TimeUnit.SECONDS)//缓存30s刷新一次(load不到新数据时仍返回旧数据)
                .build(new CacheLoader<String, List<ActivityPluginDto>>() {
                    @Override
                    public List<ActivityPluginDto> load(String s) {
                        return selectAvailableActivityPlugin();
                    }
                });

    }

    /**
     * @param pluginConfig
     * @return
     * @throws BusinessException
     */
    private List<ActivityPluginDto> getAvailableCommonPlugin(PluginToolsReq req, PlugBuoyConfigDto pluginConfig) throws BusinessException, ExecutionException {
        checkStatus(pluginConfig.getCommonPlugStatus());

        Long pluginId = null;//定制id
        if (Tenter.SOW.getCode().equals(req.getTenter()) && pluginConfig.getDirectPlugId() != null) {
            pluginId = pluginConfig.getDirectPlugId();
        } else if (Tenter.SRP.getCode().equals(req.getTenter()) && pluginConfig.getReturnInterceptPlugId() != null) {
            pluginId = pluginConfig.getReturnInterceptPlugId();
        }

        if (pluginId != null) {
            req.setCustomPlugin(true);
            ActivityPluginDto pluginDto = this.selectById(pluginId);
            if (pluginDto != null && Boolean.FALSE.equals(pluginDto.getIsDeleted()) && Boolean.TRUE.equals(pluginDto.getIsOpen())) {
                return Lists.newArrayList(pluginDto);
            }
            throw new BusinessException(ErrorCode.E0400015);
        }

        return this.availableCommonPlugin.get("plugin");
    }


    private List<ActivityPluginDto> selectAvailableActivityPlugin() {
        DubboResult<List<ActivityPluginDto>> dubboResult = remotePluginService.selectAvailableActivityPlugin();
        if (!dubboResult.isSuccess()) {
            logger.warn("remotePluginService.selectAvailableActivityPlugin error");
        }
        return dubboResult.getResult();
    }


    /**
     * 获取可用响应式插件
     * @param pluginConfig 广告位维度配置
     * @return
     * @throws BusinessException
     */
    private List<ActivityPluginDto> getAvailableResponsivePlugin(PlugBuoyConfigDto pluginConfig) throws BusinessException {
        checkStatus(pluginConfig.getRspPlugStatus());
        return this.slotService.getAvailablePlugin(pluginConfig.getRspPlugIds(), pluginConfig.getSlotId());
    }

    /*
     * 获取可用的定时插件
     * 当前时间点可出的，
     * 广告位配置的，
     * @param pluginConfig 广告位维度配置
     * @return list dto
     * @throws ExecutionException
     */
    private List<ActivityPluginDto> getAvailableTimingPlugin(PlugBuoyConfigDto pluginConfig) throws ExecutionException, BusinessException {
        checkStatus(pluginConfig.getTimingPlugStatus());

        List<Long> pluginIds = pluginConfig.getTimingPlugIds();

        if (CollectionUtils.isEmpty(pluginIds)) {
            return Collections.emptyList();
        }
        List<ActivityPluginDto> dtos = this.timingPluginCache.get(DateUtils.getMinuteOnlyStr(new Date()));

        if (CollectionUtils.isEmpty(dtos)) {
            return Collections.emptyList();
        }

        Set<Long> pluginIdSet = Sets.newHashSet(pluginIds);

        List<ActivityPluginDto> rs = Lists.newArrayList();
        dtos.forEach(dto->{
            if (pluginIdSet.contains(dto.getId())) {
                rs.add(dto);
            }
        });
        return rs;
    }

    private void checkStatus(Integer status) throws BusinessException {
        if (Integer.valueOf(1).equals(status)) {
            throw new BusinessException(ErrorCode.E0400019);
        }

    }

    @Override
    public PluginToolsRsp pluginToolsIndex(PluginToolsReq req) throws BusinessException, ExecutionException {
        // 1. 获取用户信息
        if (req.getMainPageType() == 0 && req.getPluginToolId() != null) {
            return pluginToolsPreview(req.getPluginToolId());
        }
        UserAccount consumer = RequestLocal.get().getUserAccount();
        PlugBuoyConfigDto pluginSlot = getPluginSlot(req.getIp());


        // 3.1查询可用响应式插件
        List<ActivityPluginDto> plugins = this.getAvailableCommonPlugin(req,pluginSlot);
        // 3.1 获取可用插件


        // 3.2 过滤插件
        ActivityPluginDto pluginDto = filterPluginTools(req.getHavePluginIds(), plugins, req);

        if (pluginDto == null) {
            throw new BusinessException(ErrorCode.E0400017);
        }

        // 4.返回结果（有：返回插件工具皮肤等；无：返回null）
        PluginToolsRsp rsp = this.buildPluginToolsRsp(req, pluginDto, consumer, PluginType.COMMON.getActivityType());

        // 5. 静态域名替换
        rsp.replaceDomain(req.getYunDomain());

        // 6. 访问日志记录插件id，引导页id
        AccessLogFilter.putExPair(Constants.VALUENAME.PLUGIN_ID, String.valueOf(rsp.getId()));
        AccessLogFilter.putExPair(Constants.VALUENAME.PAGE_ID, String.valueOf(req.getMainPageId()));
        String dpm = DpmBuilder.pluginBuild(consumer.getAppId());
        String dcm = DcmBuilder.pluginBuild(rsp.getId(),req.getMainPageId(),req.getMainPageType());
        AccessLogFilter.putExPair("dpm",dpm);
        AccessLogFilter.putExPair("dcm",dcm);

        // 记录地域信息
        AccessLogFilter.putExPair("area_code",this.slotService.findRegionByIp(req.getIp()));
        //记录链路信息
        directPageSourceService.log(consumer.getUserId());

        // 7.cat记录插件活动请求次数
        Cat.logMetricForCount(PLUGIN_INDEX_CAT);

        return rsp;
    }

    @Override
    public PluginToolsRsp embeddedIndex(PluginToolsReq req) throws BusinessException {
        // 1. 获取用户信息
        UserAccount consumer = RequestLocal.get().getUserAccount();
        String slotStr = RequestLocal.get().getSlotIdByAppId(RequestLocal.get().getAppId());
        if (!StringUtils.isNumeric(slotStr)) {
            throw new BusinessException(ErrorCode.E0400020);
        }
        Long slotId = Long.parseLong(slotStr);

        // 2. 预览 特殊处理
        if (req.getMainPageType() == 0 && req.getPluginToolId() != null) {
            return pluginToolsPreview(req.getPluginToolId());
        }

        // 3. 查询嵌入式工具list
        DubboResult<List<ActivityPluginDto>> pluginDubboResult = this.remotePluginService.selectAvailableEmbeddedPlugin(req.getMainPageId(), req.getBlockName());
        if (!pluginDubboResult.isSuccess() || CollectionUtils.isEmpty(pluginDubboResult.getResult())) {
            throw new BusinessException(ErrorCode.E0400013);
        }

        // 3.过滤合适的嵌入式插件
        // 3.1  获取用户已参与过的插件工具
        // json格式 id：num,id:num
        // 插件参与次数 前端保存
        String timePluginIds = req.getCount();

        ActivityPluginDto pluginDto = filterEmbeddedTools(timePluginIds, pluginDubboResult.getResult(), slotId);
        if (pluginDto == null) {
            throw new BusinessException(ErrorCode.E0400017);
        }

        // 4. 构造返回结果
        PluginToolsRsp rsp = this.buildPluginToolsRsp(req, pluginDto, consumer, PluginType.EMBEDDED.getActivityType());
        // 5. 静态域名替换
        rsp.replaceDomain(req.getYunDomain());
        AccessLogFilter.putExPair(Constants.VALUENAME.PLUGIN_ID, String.valueOf(rsp.getId()));
        AccessLogFilter.putExPair(Constants.VALUENAME.PAGE_ID, String.valueOf(req.getMainPageId()));
        // 6.添加曝光插件曝光埋点
        String dpm = DpmBuilder.pluginBuild(consumer.getAppId());
        String dcm = DcmBuilder.pluginBuild(rsp.getId(),req.getMainPageId(),req.getMainPageType());
        AccessLogFilter.putExPair("dpm",dpm);
        AccessLogFilter.putExPair("dcm",dcm);

        // 记录地域信息
        AccessLogFilter.putExPair("area_code",this.slotService.findRegionByIp(req.getIp()));
        //记录链路信息
        directPageSourceService.log(consumer.getUserId());

        // 7.cat记录插件活动请求次数
        Cat.logMetricForCount(PLUGIN_INDEX_CAT);

        return rsp;
    }

    @Override
    public PluginToolsRsp responsiveIndex(PluginToolsReq req) throws BusinessException, ExecutionException {
        // 1. 获取用户信息
        if (req.getMainPageType() == 0 && req.getPluginToolId() != null) {
            return pluginToolsPreview(req.getPluginToolId());
        }
        UserAccount consumer = RequestLocal.get().getUserAccount();
        PlugBuoyConfigDto pluginSlot = getPluginSlot(req.getIp());
        // 3.1查询可用响应式插件
        List<ActivityPluginDto> plugins = this.getAvailableResponsivePlugin(pluginSlot);

        // 4.过滤响应式插件
        ActivityPluginDto plugin = filterPluginList(req, plugins, consumer, pluginSlot);
        if (null == plugin) {
            throw new BusinessException(ErrorCode.E0400015);
        }

        // 5.构建返回
        PluginToolsRsp rsp = this.buildPluginToolsRsp(req, plugin, consumer, PluginType.RESPONSIVE.getActivityType());
        // 6.静态域名替换
        rsp.replaceDomain(req.getYunDomain());

        // 7.cat记录插件活动请求次数
        Cat.logMetricForCount(PLUGIN_INDEX_CAT);
        AccessLogFilter.putExPair(Constants.VALUENAME.PLUGIN_ID, plugin.getId().toString());
        AccessLogFilter.putExPair(Constants.VALUENAME.PAGE_ID, String.valueOf(req.getMainPageId()));
        // 8.添加曝光插件曝光埋点
        String dpm = DpmBuilder.pluginBuild(consumer.getAppId());
        String dcm = DcmBuilder.pluginBuild(rsp.getId(),req.getMainPageId(),req.getMainPageType());
        AccessLogFilter.putExPair("dpm",dpm);
        AccessLogFilter.putExPair("dcm",dcm);
        // 记录地域信息
        AccessLogFilter.putExPair("area_code",this.slotService.findRegionByIp(req.getIp()));
        //记录链路信息
        directPageSourceService.log(consumer.getUserId());
        return rsp;
    }

    @Override
    public PluginToolsRsp timingIndex(PluginToolsReq req) throws BusinessException, ExecutionException {

        // 2. 预览 特殊处理
        if (req.getMainPageType() == 0 && req.getPluginToolId() != null) {
            return pluginToolsPreview(req.getPluginToolId());
        }
        UserAccount consumer = RequestLocal.get().getUserAccount();
        // 1. 获取用户信息
        List<ActivityPluginDto> dtos = this.getAvailableTimingPlugin(getPluginSlot(req.getIp()));

        // 4. 过滤定时插件
        ActivityPluginDto plugin = filterTimingPluginList(req, dtos);
        if (null == plugin) {
            throw new BusinessException(ErrorCode.E0400015);
        }
        // 5. 构建返回结果
        PluginToolsRsp rsp = this.buildPluginToolsRsp(req, plugin, consumer, PluginType.TIMINGPLUGIN.getActivityType());

        // 6. 静态域名替换
        rsp.replaceDomain(req.getYunDomain());

        // 7. 访问日志记录插件id
        AccessLogFilter.putExPair(Constants.VALUENAME.PLUGIN_ID, String.valueOf(rsp.getId()));
        AccessLogFilter.putExPair(Constants.VALUENAME.PAGE_ID, String.valueOf(req.getMainPageId()));
        // 8. 添加曝光插件曝光埋点
        String dpm = DpmBuilder.pluginBuild(consumer.getAppId());
        String dcm = DcmBuilder.pluginBuild(rsp.getId(),req.getMainPageId(),req.getMainPageType());
        AccessLogFilter.putExPair("dpm",dpm);
        AccessLogFilter.putExPair("dcm",dcm);
        // 记录地域信息
        AccessLogFilter.putExPair("area_code",this.slotService.findRegionByIp(req.getIp()));
        //记录链路信息
        directPageSourceService.log(consumer.getUserId());
        // 9.cat记录插件活动请求次数
        Cat.logMetricForCount(PLUGIN_INDEX_CAT);

        return rsp;
    }

    private PlugBuoyConfigDto getPluginSlot(String ip) throws BusinessException {
        String slotStr = RequestLocal.get().getSlotIdByAppId(RequestLocal.get().getAppId());
        if (!StringUtils.isNumeric(slotStr)) {
            throw new BusinessException(ErrorCode.E0400020);
        }
        Long slotId = Long.parseLong(slotStr);

        // 3.查询广告位插件配置
        Optional<SlotDto> optional =this.slotService.getSlot(slotId);
        if(!optional.isPresent() || optional.get().getPlugBuoyConfigDto() == null){
            throw new BusinessException(ErrorCode.E0400020);
        }
        if (!this.slotService.ipFilter(optional.get(), ip, Scene.PLUGIN)) {
            throw new BusinessException(ErrorCode.E0400021);
        }

        // 3.1 获取可用插件
        return optional.get().getPlugBuoyConfigDto();
    }

    /**
     * 构造返回
     *
     * @param req      请求参数
     * @param plugin   插件dto
     * @param consumer 用户
     * @return rsp
     * @throws ActivityException 活动异常
     */
    private PluginToolsRsp buildPluginToolsRsp(PluginToolsReq req, ActivityPluginDto plugin, UserAccount consumer, Integer activityType) throws BusinessException {

        //查询插件皮肤
        PluginSkinDto pluginSkinDto = this.selectSkinBySkinId(plugin.getSkinId());
        //构造响应数据
        PluginToolsRsp rsp = buildPluginEmbed(consumer, req, plugin);
        rsp.setId(plugin.getId());
        rsp.setIsNew(false);
        rsp.setSkinConfig(pluginSkinDto.getCode());
        rsp.setSkinName(pluginSkinDto.getSkinName());
        rsp.setSkinId(pluginSkinDto.getId());
        rsp.setTitle(plugin.getTitle());
        rsp.setTriggerType(plugin.getTriggerType());
        rsp.setTriggerUrl(plugin.getTriggerUrl());
        rsp.setType(activityType);

        rsp.setPriority(plugin.getPriority());
        return rsp;
    }

    /**
     * 根据皮肤id 查询皮肤
     */
    private PluginSkinDto selectSkinBySkinId(long skinId) throws BusinessException {
        //查询插件皮肤
        DubboResult<PluginSkinDto> pluginSkinResult = remotePluginService.selectSkinById(skinId);
        if (!pluginSkinResult.isSuccess()) {
            throw new ActivityRuntimeException(ErrorCode.E0400000);
        }
        PluginSkinDto rs = pluginSkinResult.getResult();
        if (rs == null || Boolean.TRUE.equals(rs.getIsDeleted())) {
            throw new BusinessException(ErrorCode.E0400016);
        }
        return rs;
    }

    @Override
    public List<ActivityPluginDto> selectAvailablePluginByMinuteAndType(PluginType pluginType) throws ActivityException {
        List<ActivityPluginDto> rs = Lists.newArrayList();
        DubboResult<List<ActivityPluginDto>> dr = this.remotePluginService.selectAvailablePluginByMinute();
        if (!dr.isSuccess()) {
            throw new ActivityRuntimeException(ErrorCode.E0400000);
        }
        List<ActivityPluginDto> dtos = dr.getResult();
        if (CollectionUtils.isNotEmpty(dtos)) {
            dtos.forEach(dto -> {
                if (pluginType.getType().equals(dto.getPluginType())) {
                    rs.add(dto);
                }
            });
        }
        Collections.emptyList();
        return rs;
    }

    @Override
    public ActivityPluginDto selectById(Long id) throws ExecutionException {
        return this.pluginCache.get(id);
    }

    /**
     * 构建埋点数据
     *
     * @param consumer 用户
     * @param req 请求参数
     * @param plugin 插件
     * @return rsp
     */
    private PluginToolsRsp buildPluginEmbed(UserAccount consumer, PluginToolsReq req, ActivityPluginDto plugin) {
        // 3.构建埋点数据
        String dpm = DpmInfo.getDpmInfo(consumer.getAppId(), Constants.DPM.DPM_B_38, Constants.DPM.DPM_C_1, Constants.DPM.DPM_D_0);
        String dpmClose = DpmInfo.getDpmInfo(consumer.getAppId(), Constants.DPM.DPM_B_38, Constants.DPM.DPM_C_1, Constants.DPM.DPM_D_1);
        String dcm = DpmInfo.dcmInfo(Constants.DCM.DPM_A_702, plugin.getId(), req.getMainPageType(), req.getMainPageId());

        // 4.将埋点信息放入cookie
        CookieUtil.putDmCookie(Constants.COOKIEKEY.PLUGIN,String.valueOf(plugin.getId()),getDsmFromReferer(req.getReferer()),dcm,dpm);

        String stEmbed = DpmInfo.setStPluginInfo(consumer.getAppId(), consumer.getUserId(), dpm, dcm, "//" + req.getHost(),null);
        String stClose = DpmInfo.setStPluginClick(consumer.getAppId(), consumer.getUserId(), "//" + req.getHost(), dpmClose, dcm,null);
        String moreClickEmbedData = PluginEmbed.stPluginBtnMoreClick(consumer.getAppId(), consumer.getUserId(), req.getMainPageId(), plugin.getId(), "//" + req.getHost(),req.getMainPageType());
        String moreEmbedData = PluginEmbed.stPluginBtnMoreExposure(consumer.getAppId(), consumer.getUserId(), req.getMainPageId(), plugin.getId(),req.getMainPageType());
        PluginToolsRsp rsp = new PluginToolsRsp();
        rsp.setEmbedData(stEmbed);
        rsp.setCloseClickEmbedData(stClose);
        rsp.setMoreClickEmbedData(moreClickEmbedData);
        rsp.setMoreEmbedData(moreEmbedData);
        return rsp;
    }

    /**
     * 响应式插件过滤
     */
    private ActivityPluginDto filterPluginList(PluginToolsReq req, List<ActivityPluginDto> plugins, UserAccount consumer,PlugBuoyConfigDto pluginConfig) {
        if (CollectionUtils.isEmpty(plugins)) {
            return null;
        }

        // 广告位下配置的插件等概率出
        Collections.shuffle(plugins);

        List<ResponsiveJoinTimes> joinTimes = JSONObject.parseArray(req.getJoinTimes(), ResponsiveJoinTimes.class);
        Map<Long, ResponsiveJoinTimes> joinTimesMap = EntityUtil.transf(null == joinTimes ? ListUtils.EMPTY_LIST : joinTimes, ResponsiveJoinTimes::getId);
        Map<Object, Object> consumerActivityDojoinCacheMap = activityService.getConsumerActivityDojoinCacheMap(consumer.getUserId());

        //广告位配置的活动参与次数，优先级大于活动配置
        Integer slotJoinTimes = pluginConfig.getRspPlugCount();
        for (ActivityPluginDto dto : plugins) {

            ResponsiveJoinTimes joinTime = joinTimesMap.get(dto.getId());
            //3.插件被该用户关闭或参与过不展示
            //4.用户曝光过该插件，且改插件为只展示一次类型，不展示
            if (checkNotShow(req, consumerActivityDojoinCacheMap, dto, joinTime,slotJoinTimes)) {
                continue;
            }

            //6.在可以出现的插件列表中返回id最大的插件
            return dto;
        }
        return null;
    }

    private ActivityPluginDto filterTimingPluginList(PluginToolsReq req, List<ActivityPluginDto> plugins) {

        if (CollectionUtils.isEmpty(plugins)) {
            return null;
        }

        // 广告位下配置的插件等概率出
        Collections.shuffle(plugins);

        List<ResponsiveJoinTimes> joinTimes = JSONObject.parseArray(req.getJoinTimes(), ResponsiveJoinTimes.class);
        Map<Long, ResponsiveJoinTimes> joinTimesMap = EntityUtil.transf(null == joinTimes ? ListUtils.EMPTY_LIST : joinTimes, ResponsiveJoinTimes::getId);

        for (ActivityPluginDto dto : plugins) {
            ResponsiveJoinTimes joinTime = joinTimesMap.get(dto.getId());
            // 插件被该用户关闭或参与过不展示
            if (checkCloseAndJoin(dto, joinTime)) {
                continue;
            }
            return dto;
        }
        return null;
    }

    private boolean checkCloseAndJoin(ActivityPluginDto dto, ResponsiveJoinTimes joinTime) {
        if (joinTime == null) {
            return false;
        }

        if (Boolean.TRUE.equals(joinTime.getCloseOrJoin())) {
            return true;//用户关闭过
        }

        return dto.getJoinTime() != null && joinTime.getCount() != null && joinTime.getCount() >= dto.getJoinTime();
    }

    private boolean checkNotShow(PluginToolsReq req, Map<Object, Object> consumerActivityDojoinCacheMap, ActivityPluginDto dto, ResponsiveJoinTimes joinTime,Integer slotJoinTimes) {
        if (null != joinTime && (joinTime.getCloseOrJoin() || ResponsiveAppearType.ONE_TIME.getType() == dto.getAppearType())) {
            return true;
        }
        //过滤插件和用户的参与次数
        //3.响应式插件设置触发次数时，获取用户参与he当前活动的次数，触发次数大于当前参与次数时不展示
        Integer joinTimes = slotJoinTimes;
        if (null == joinTimes) {
            joinTimes = dto.getJoinTime();
        }

        if (null != joinTimes) {
            Object consumerActivityDojoinTimesCache = consumerActivityDojoinCacheMap.get(req.getMainPageId().toString());
            int consumerActivityDojoinTimes = 0;
            if (null != consumerActivityDojoinTimesCache) {
                consumerActivityDojoinTimes = Integer.valueOf(consumerActivityDojoinTimesCache.toString());
            }
            if (joinTimes > consumerActivityDojoinTimes) {
                return true;
            }
        }
        return false;
    }

    /**
     * filterPluginTools:过滤合适的插件工具. <br/>
     *
     * @param pluginToolsList 插件dtos
     * @return 适合的插件工具
     * @author cdm
     */
    private ActivityPluginDto filterPluginTools(String havePluginIds, List<ActivityPluginDto> pluginToolsList, PluginToolsReq req) {

        // 当前时间
        Calendar currentHour = Calendar.getInstance();

        // 获取小时对应的参与数
        List<PluginTimeNum> timesList = JSONObject.parseArray(req.getTimeNum(), PluginTimeNum.class);

        // 1.循环过滤插件工具
        for (ActivityPluginDto pluginTools : pluginToolsList) {

            // 1.1 判断是否领取过
            if (havePluginIds != null && havePluginIds.contains(String.valueOf(pluginTools.getId()))) {
                continue;
            }

            //1.3 该流量引导页是否有定向插件
            if (!req.isCustomPlugin() && checkScenarios(pluginTools, req)) {
                continue;
            }

            // 1.4 判断时间点 和次数
            if (checkPluginToolsPeriod(currentHour, pluginTools.getPeriodList(), timesList, pluginTools.getTriggerEvent())) {
                return pluginTools;
            }
        }

        return null;
    }


    /**
     * 匹配流量引导页定向
     *
     * @param pluginTools 插件dto
     * @param req 请求参数
     * @return boolean
     */
    private Boolean checkScenarios(ActivityPluginDto pluginTools, PluginToolsReq req) {

        // 1.3 判断该流量引导页是否有定向插件
        if (pluginTools.getScenarios() != null) {
            String[] scenarios = pluginTools.getScenarios().split(",");
            List<String> scenariosList = Arrays.asList(scenarios);
            if (!scenariosList.contains(String.valueOf(req.getMainPageId()))) {
                return Boolean.TRUE;
            }
        }
        return Boolean.FALSE;
    }

    /**
     * 过滤 可出 的嵌入式插件
     *
     * @param timePluginIds 参与次数，存在cookies中
     * @param pluginToosList 插件list
     * @param slotId 广告位
     * @return dto
     */
    private ActivityPluginDto filterEmbeddedTools(String timePluginIds, List<ActivityPluginDto> pluginToosList, Long slotId) {

        for (ActivityPluginDto pluginTools : pluginToosList) {
            // 校验广告位定向 (如果开启并配置了广告位定向，则只在定向的媒体中出)
            if (!checkSlotDirect(pluginTools, slotId)) {
                continue;
            }

            // 校验参与次数(嵌入式插件活动，每个用户参与某个插件次数达到 配置的showTimes后，不可再出)
            if (!checkJoinTimes(pluginTools, timePluginIds)) {
                continue;
            }

            return pluginTools;
        }

        return null;
    }


    /**
     * 广告位定向
     *
     * @param dto 插件dto
     * @param slotId 广告位id
     * @return boolean
     */
    private boolean checkSlotDirect(ActivityPluginDto dto, Long slotId) {
        return Boolean.FALSE.equals(dto.getIsDirect()) || StringTool.isContainFromCommaStr(dto.getDirectSlot(), slotId);
    }


    /**
     * 校验嵌入式插件参与次数
     *
     * @param dto 插件dto
     * @param timePluginIds cookie 中存储
     * @return 校验通过：true,校验pass:false;
     */
    private boolean checkJoinTimes(ActivityPluginDto dto, String timePluginIds) {
        if (StringUtils.isBlank(timePluginIds)) {
            return true;
        }
        JSONObject json = JSONObject.parseObject(timePluginIds);
        Integer times = json.getInteger(String.valueOf(dto.getId()));
        return times == null || dto.getShowTime() == null || times < dto.getShowTime();

    }

    /**
     * checkPluginToolsPeriod:验证当前时间段是否有插件工具可展示. <br/>
     *
     * @param currtHour 当前时间的 小时
     * @param periodList 插件工具定向时间段
     * @return
     * @author cdm
     * @since JDK 1.7
     */
    private Boolean checkPluginToolsPeriod(Calendar currtHour, List<PeriodDto> periodList, List<PluginTimeNum> timeslist, Integer triggerEvent) {
        // 1.循环判断时间
        if (periodList != null) {
            // 如果size等于0 ，表示 0-24点时间段，那么一定在此时间段内
            Integer times = 0;

            // 0-24点判断逻辑
            if (periodList.isEmpty()) {
                // 判断次数 , 所有的时间段相加
                if (!CollectionUtils.isEmpty(timeslist)) {
                    for (PluginTimeNum timeNum : timeslist) {
                        times += timeNum.getCount();
                    }
                }
                return times == triggerEvent;
            }

            // 时间段判断逻辑
            if (checkPeriod(currtHour, periodList, timeslist, triggerEvent, times)) {
                return true;
            }
        }
        return false;
    }

    private boolean checkPeriod(Calendar currentHour, List<PeriodDto> periodList, List<PluginTimeNum> timesList, Integer triggerEvent, Integer times) {
        Integer timesCount = times;
        for (PeriodDto periodDto : periodList) {
            if (DateUtils.betweenHHmm(currentHour, periodDto.getDateStart(), periodDto.getDateEnd()) == 1) {
                // 根据开始时间和结束时间累加  2. 判断次数
                for (PluginTimeNum timeNum : timesList) {
                    if (timeNum.getHour() >= DateUtils.getHour(periodDto.getStart()) && timeNum.getHour() <= DateUtils.getHour(periodDto.getEnd())) {
                        timesCount += timeNum.getCount();
                    }
                }
                if (timesCount == triggerEvent) {
                    return true;
                }
            }
        }
        return false;
    }


    /**
     * pluginToolsPreview:(这里用一句话描述这个方法的作用). <br/>
     * 预览特殊处理
     *
     * @param pluginToolsId 插件id
     * @throws ActivityException 活动异常
     * @author cdm
     * @since JDK 1.7
     */
    public PluginToolsRsp pluginToolsPreview(Long pluginToolsId) throws BusinessException {
        // 1.remotePluginService
        DubboResult<ActivityPluginDto> pluginDubboResult = remotePluginService.selectActivityPluginById(pluginToolsId);
        if (!pluginDubboResult.isSuccess() || pluginDubboResult.getResult() == null || pluginDubboResult.getResult().getIsDeleted() == null || pluginDubboResult.getResult().getIsDeleted()) {
            throw new BusinessException(ErrorCode.E0400018);
        }

        ActivityPluginDto pluginDto = pluginDubboResult.getResult();

        // 1.获取插件工具皮肤
        DubboResult<PluginSkinDto> pluginSkinResult = remotePluginService.selectSkinById(pluginDto.getSkinId());
        if (pluginSkinResult.getResult() == null || pluginSkinResult.getResult().getIsDeleted()) {
            return null;
        }

        PluginSkinDto pluginSkinDto = pluginSkinResult.getResult();

        // 3.返回结果（有：返回插件工具皮肤等；无：返回null）
        // 3.1  构建data返回数据对象
        PluginToolsRsp rsp = new PluginToolsRsp();
        if (StringUtils.isNotBlank(RequestLocal.get().getSlotId()) && !"null".equals(RequestLocal.get().getSlotId())) {
            rsp.setSlotId(Long.valueOf(RequestLocal.get().getSlotId()));
        }
        rsp.setId(pluginDto.getId());
        rsp.setIsNew(false);
        rsp.setSkinConfig(pluginSkinDto.getCode());
        rsp.setSkinName(pluginSkinDto.getSkinName());
        rsp.setSkinId(pluginSkinDto.getId());
        rsp.setTitle(pluginDto.getTitle());
        rsp.setTriggerType(pluginDto.getTriggerType());
        rsp.setTriggerUrl(pluginDto.getTriggerUrl());
        rsp.setType(Constants.PLUGIN_TOOLS_TYPE);
        return rsp;
    }

    @Override
    public JSONObject doJoin(DoJoinActivityReq doJoinActivityReq, HttpServletRequest request) throws ActivityException {

        // 2.用户验证
        commonService.checkConsumer(doJoinActivityReq.getActivityId(), doJoinActivityReq.getConsumerId(), null, Scene.PLUGIN);

        // 3.获取插件奖项
        List<ActivityOptionDto> options = this.selectPluginOptions(doJoinActivityReq.getActivityId());

        // 4.生成订单
        RspOrder rspOrder = null;
        try {
            // 4.生成订单
            rspOrder = activityOrderService.createPluginToolsOrder(doJoinActivityReq);
            // 5.异步中奖
            commonService.doJoin(rspOrder, doJoinActivityReq, options);

            // 6.用户参与过的插件工具放入cookie  第二天失效 ，更新用户已参与过的插件工具id列表
            updateFinishedPluginIdList(request, doJoinActivityReq.getActivityId(), doJoinActivityReq.getConsumerId());
        } catch (Exception e) {
            logger.warn("用户参与活动失败.", e);
            throw new ActivityException(ErrorCode.E9999999.geteCode(), Constants.NETWORK_ERROR);
        }
        // 构建抽奖订单结果
        // 返回订单ID和结果状态
        JSONObject result = new JSONObject();
        DmCookieHolder dmCookie = CookieUtil.getDmCookie(Constants.COOKIEKEY.PLUGIN, String.valueOf(doJoinActivityReq.getActivityId()));
        if(dmCookie!=null){
            AccessLogFilter.putExPair("dpm",dmCookie.getDpm());
            AccessLogFilter.putExPair("dcm",dmCookie.getDcm());
        }

        // 记录地域信息
        AccessLogFilter.putExPair("area_code",this.slotService.findRegionByIp(doJoinActivityReq.getIp()));
        //记录链路信息
        directPageSourceService.log(doJoinActivityReq.getConsumerId());

        result.put("orderId", rspOrder.getOrderId());
        result.put("success", true);
        result.put("message", "成功");

        return result;
    }

    /**
     *
     */
    @Override
    public JSONObject result(HttpServletRequest request, String pluginToolsOrderId, Boolean showVersion) throws ActivityException {
        try {
            // 1.缓存获取参数
            Long appId = RequestLocal.get().getAppId();
            Long consumerId = RequestLocal.get().getCid();
            // 2.构建奖项结果
            return buildResultRsp(request, pluginToolsOrderId, appId, consumerId, showVersion);
        } catch (ActivityException e) {
            logger.warn("获取活动验证失败,活动获取不到或活动已删除", e);
            throw new ActivityException(ErrorCode.E0200005.geteCode(), Constants.NETWORK_ERROR);
        }
    }

    /**
     * 新 插件奖品查询，与活动在同一个库，包含奖品
     * @param pluginId 插件id
     * @return list dto
     */
    private List<ActivityOptionDto> selectPluginOptions(Long pluginId) {
        return this.remotePluginService.selectActivityOptionByPluginId(pluginId, false).getResult();
    }


    /**
     * 构建抽奖结果.
     *
     * @param request request
     * @param orderId order id
     * @param appId app id
     * @param consumerId consumer id
     * @param show show version
     * @return the JSON object
     * @throws ActivityException the activity exception
     */
    private JSONObject buildResultRsp(HttpServletRequest request, String orderId, Long appId, Long consumerId,
                                      Boolean show) throws ActivityException {

        Map<String, Object> lottery = Maps.newHashMap();
        JSONObject jsonObject = new JSONObject();
        // 如果没有新弹层，默认false
        boolean showVersion = show == null ? false : show;

        // 3.1.获取保存在cookie中的活动页来源
        ActivityOrderDto activityOrderDto = checkConsumerAndOrder(orderId, consumerId);

        // 2.3 根据奖项ID，奖项类型，判断中奖流程是否走完。 返回成功、失败、等待三种状态
        if (null == activityOrderDto.getPrizeType() || "null".equals(String.valueOf(activityOrderDto.getPrizeType()))
                || StringUtils.isEmpty(String.valueOf(activityOrderDto.getPrizeType()))) {
            jsonObject.put("status", "wait");
            jsonObject.put("message", "成功-等待");
            return jsonObject;
        }

        String orderOptionType = activityOrderDto.getPrizeType();
        if (ActivityOptionType.TYPE_THANKS.getCode().equals(orderOptionType)) {
            // 3.1 如果为谢谢参与
            jsonObject.put(Constants.VALUENAME.RESULT, Constants.LOTTERYCODE.LOTTERY_CODE_0);

        } else if (ActivityOptionType.TYPE_AGAIN.getCode().equals(orderOptionType)) {
            // 3.2 如果为再来一次
            jsonObject.put(Constants.VALUENAME.RESULT, Constants.LOTTERYCODE.LOTTERY_CODE_1);
            jsonObject.put("againTag", orderId);
        } else if (ActivityOptionType.TYPE_LUCKY.getCode().equals(activityOrderDto.getPrizeType())
                || ActivityOptionType.TYPE_COUPON.getCode().equals(activityOrderDto.getPrizeType())) {
            // 4.如果奖项是福袋或者推啊券
            // 4.1查询奖项信息
            if (null == activityOrderDto.getPrizeId()) {
                JSONObject json = JSONObject.parseObject(activityOrderDto.getCouponData());
                // 4.2构建奖项信息, "使用详情"链接
                lottery.put(Constants.VALUENAME.IMG_URL, DomainUtil.replaceDomain(json.getString(Constants.VALUENAME.THUMBNAIL_PNG),
                        DomainUtil.getCurrentYunDomain(request)));//图片域名替换
                lottery.put("isDownloadUrl", true);
                lottery.put("linkTo", ItemDto.LinkToBussiness);
                lottery.put(Constants.VALUENAME.TITLE, json.get(Constants.VALUENAME.TITLE));
            } else {
                ActivityOptionDto orderOptionDto = activityService.selectActivityOption(activityOrderDto.getPrizeId());
                // 4.2构建奖项信息, "使用详情"链接
                lottery.put(Constants.VALUENAME.IMG_URL, DomainUtil.replaceDomain(orderOptionDto.getImage(),
                        DomainUtil.getCurrentYunDomain(request)));//图片域名替换
                lottery.put("isDownloadUrl", true);
                lottery.put("linkTo", ItemDto.LinkToBussiness);
                lottery.put(Constants.VALUENAME.TITLE, orderOptionDto.getTitle());
            }
            // 4.3推啊券的构造抽奖结果
            jsonObject.put(Constants.VALUENAME.RESULT, Constants.LOTTERYCODE.LOTTERY_CODE_2);
            Long slotId = null;
            if (StringUtils.isNotBlank(RequestLocal.get().getSlotId())) {
                slotId = Long.valueOf(RequestLocal.get().getSlotId());
            }
            QueryAdvertRsp advert = luckBagService.queryAdvert(consumerId, orderId, 1, slotId);
            if (null == advert) {
                logger.warn("查询广告信息失败。JoinActivityBOImpl---》buildResultRsp---》queryAdvert is null");
                throw new ActivityException(ErrorCode.E9999999);
            }
            buildDoJoinRspForTuiaCoupon(request, lottery, activityOrderDto, appId, consumerId, advert,
                    activityOrderDto.getActivityId(), showVersion);
        }

        // 5.奖项ID和奖项类型,订单ID
        lottery.put("id", activityOrderDto.getPrizeId());
        lottery.put("type", orderOptionType);
        jsonObject.put("orderId", orderId);
        jsonObject.put("lottery", lottery);
        jsonObject.put("status", "success");

        return jsonObject;
    }

    private ActivityOrderDto checkConsumerAndOrder(String orderId, Long consumerId) throws ActivityException {
        // 1.检查用户信息
        if (null == consumerId || StringUtils.isEmpty(String.valueOf(consumerId))) {
            logger.warn("用户信息异常。consumerId is null");
            throw new ActivityException(ErrorCode.E0200005);
        }

        // 2.校验插件订单号
        if(!checkOrderId(orderId)){
            logger.warn("插件订单号异常。orderId is error   and order id is {}", orderId);
            throw new ActivityException(ErrorCode.E0200005);
        }

        // 3.通过(用户ID和订单ID)查询订单信息
        ActivityOrderDto activityOrderDto = activityOrderService.selectByIdAndConsumerId(orderId, consumerId);
        // 3.1 校验权限(用户信息仅用于查询订单时分表)
        if (null != activityOrderDto && null != activityOrderDto.getConsumerId()
                && !activityOrderDto.getConsumerId().equals(consumerId)) {
            logger.warn("权限异常，访问用户和下单用户ID不一致。consumerId not  equals activityOrderDto.getConsumerId()");
            throw new ActivityException(ErrorCode.E0200005);
        }
        // 3.2 是否有订单信息
        if (null == activityOrderDto) {
            logger.warn("无订单信息。activityOrderDto  is null ");
            throw new ActivityException(ErrorCode.E0200005);
        }
        return activityOrderDto;
    }

    /**
     * checkOrderId:(这里用一句话描述这个方法的作用). <br/>
     *
     * @param orderId
     * @return
     */
    private Boolean checkOrderId(String orderId) {
        // 1.订单号非空和长度校验
        if (null == orderId || orderId.length() < 5 || orderId.length() > 19) {
            logger.error("非法插件订单号，error  orderId is {}", orderId);
            return false;
        }

        // 2.截取orderId 获取后四位，作为表后缀校验
        String orderIdSuffix = orderId.substring(orderId.length() - 4);
        Long orederTb = Long.valueOf(orderIdSuffix);

        return orederTb < 1024;
    }


    /**
     * 构造抽奖结果.
     *
     * @param request the request
     * @param lottery the lottery
     * @param activityOrderDto the activity order id
     * @param appId the app id
     * @param consumerId the consumer id
     * @param advert the advert
     * @param activityId the activity id
     * @param showVersion 展示版本 false：旧弹层 ； true：新弹层
     * @throws ActivityException the activity exception
     */
    private void buildDoJoinRspForTuiaCoupon(HttpServletRequest request, Map<String, Object> lottery,
                                             ActivityOrderDto activityOrderDto, Long appId, Long consumerId,
                                             QueryAdvertRsp advert, Long activityId, Boolean showVersion)
            throws ActivityException {

        String activityOrderId = activityOrderDto.getOrderId();

        // 1.得到推啊券的标题和副标题
        lottery.put("tip", advert.getViceTitle());
        lottery.put(Constants.VALUENAME.TITLE, advert.getTitle());

        // 2.得到推啊券的马上使用按钮文案
        buildBtnText(lottery, advert);

        int d = showVersion?Constants.DPM.DPM_D_1:Constants.DPM.DPM_D_0;

        // 3.马上使用&马上使用状态下的图片（曝光+访问）dpm=app_id.4.1.0;dcm=104.advertId.0.0
        String dpm = DpmInfo.getDpmInfo(appId, Constants.DPM.DPM_B_4, Constants.DPM.DPM_C_1, d);
        String dcm = DpmInfo.getDcmInfo(advert.getAdvertId(), advert.getMaterialId());
        String dsm = null;
        DmCookieHolder dmCookie = CookieUtil.getDmCookie(Constants.COOKIEKEY.PLUGIN, String.valueOf(activityId));
        if(dmCookie!=null){
            dsm=dmCookie.getDsm();
        }

        String promoteUrl = EmbedUtil.getEncryptUrl(advert.getPromoteUrl(), consumerId);
        boolean showUse = false;
        lottery.put("link", getLink("//" + request.getHeader("host"), activityOrderId, appId, dcm));
        // 4.如果为可重复使用码或者普通优惠码
        if (advert.getCouponType() == 2 || advert.getCouponType() == 3) {

            // 4.1 如果为微信券
            if (advert.getIsWeixin() == 1) {

                showUse = true;
                lottery.put(Constants.VALUENAME.USE_BTN_TEXT, "查看使用方法");
                promoteUrl = Constants.PATH.ACTIVITY + Constants.PATH.INDEX_RECORD
                        + "?vmName=detail&orderId=" + activityOrderId;
                dpm = DpmInfo.getDpmInfo(appId, Constants.DPM.DPM_B_4, Constants.DPM.DPM_C_2,
                        showVersion ? Constants.DPM.DPM_D_1 : Constants.DPM.DPM_D_0);
            }

            lottery.put("coupon_code", advert.getCodeContent());
            lottery.put("coupon_key", advert.getCodePasswd());
        }

        // 5.1 跳转url组装并urlEncode
        promoteUrl = encodePromoteUrl(promoteUrl);
        Long directpage = this.directPageSourceService.get(consumerId);
        lottery.put("st_info_dpm_img", DpmInfo.setStInfo("//" + request.getHeader("host"), appId, consumerId,
                Constants.THE_PREFIX_ORDERID + activityOrderId,
                advert.getAdvertId(), advert.getMaterialId(), activityId, dpm,
                dcm, dsm, null, null, CouponSource.PLUGIN.getCode(),
                activityOrderDto.getActivityType(), null,directpage));// 弹层图片埋点

        // 6.需要隐藏特殊网址
        showUse = getShowUse(appId, advert, promoteUrl, showUse);

        lottery.put("validate", advert.getEndValid());

        // 51信用卡不展示使用按钮
        if (appId == 16101) {
            showUse = false;
        }

        doWithShowUse(lottery,showUse,request.getHeader("host"),promoteUrl,activityOrderId,dcm,dpm,activityId);

        lottery.put(Constants.VALUENAME.IMG_URL, advert.getBannerPngUrl());

    }

    private void doWithShowUse( Map<String, Object> lottery,boolean showUse,String host,String promoteUrl,String activityOrderId,
                                String dcm,String dpm,Long activityId){
        lottery.put("showUse", showUse);

        if (showUse) {
            lottery.put("openUrl", "");

            // 7.跳转web中间页
            promoteUrl = PathUtil.getButtonUrl("//" + host, promoteUrl, activityOrderId, dcm, dpm,
                    activityId, CouponSource.PLUGIN.getCode(), null);
            lottery.put("iosDownloadUrl", promoteUrl);
            lottery.put("androidDownloadUrl", promoteUrl);
        }

    }

    private boolean getShowUse(Long appId, QueryAdvertRsp advert, String promoteUrl, boolean showUse) {
        boolean rs = showUse;
        if (advert.getSpecialHide() == 1) {
            // 6.1如果为普通券和可重复使用券并且为微信券， 则展示
            if ((advert.getCouponType() == 2 || advert.getCouponType() == 3) && advert.getIsWeixin() == 1) {
                rs = true;
            } else if (advert.getCouponType() != 1) {
                // 6.2如果为普通券和可重复使用券并且但不为微信券
                rs = !AppIdConstant.showUseButton.contains(appId);
            }

        } else if (StringUtils.isNotBlank(promoteUrl)) {
            // 6.3如果推广网址不为空， 则展示
            rs = true;
        }
        return rs;
    }

    private String encodePromoteUrl(String promoteUrl) throws ActivityException {
        try {
            return URLEncoder.encode(promoteUrl, "utf-8");
        } catch (UnsupportedEncodingException e) {
            throw new ActivityException(e);
        }
    }

    private void buildBtnText(Map<String, Object> lottery, QueryAdvertRsp advert) {
        if (StringUtils.isBlank(advert.getButtonText())) {
            lottery.put(Constants.VALUENAME.USE_BTN_TEXT, "马上使用");
        } else {
            lottery.put(Constants.VALUENAME.USE_BTN_TEXT, advert.getButtonText());
        }
    }


    /**
     * Gets the link.
     *
     * @param host the host
     * @param orderId the order id
     * @param appId the app id
     * @param dcm the dcm
     * @return the link
     */
    private String getLink(String host, String orderId, Long appId, String dcm) {
        StringBuilder builder = new StringBuilder();
        builder.append(host).append(Constants.PATH.ACTIVITY).append(Constants.PATH.INDEX_RECORD).append("?vmName=detail&orderId=").append(orderId);
        builder.append("&dpm=");
        builder.append(DpmInfo.getDpmInfo(appId, Constants.DPM.DPM_B_4, Constants.DPM.DPM_C_3,
                Constants.DPM.DPM_D_0));
        builder.append("&dcm=");
        builder.append(dcm);

        return builder.toString();

    }

    /**
     * 更新已参与过的插件工具ID
     */
    @Override
    public void updateFinishedPluginIdList(HttpServletRequest request, Long pluginToolsId, Long consumerId) throws ActivityException {
        // 1. 获取cookie中的已参与过的插件工具ID
        RequestLocal.get().setRequest(request);
        String finishIds = "";
        Cookie cookie = CookieUtil.getCookieByName(request, Constants.FINISHED_PLUGIN_ID_KEY + consumerId);
        String ids = cookie == null ? null : cookie.getValue();

        if (StringUtils.isEmpty(ids) || "null".equals(ids)) {
            finishIds += pluginToolsId;
        } else {
            finishIds = ids + "," + pluginToolsId;
        }


        // 2. 设置今天过期的插件工具ID缓存cookie0
        // 2.1 获取当前时间
        Calendar curDate = Calendar.getInstance();
        // 2.2 获取明天时间
        Calendar tommorowDate = new GregorianCalendar(curDate
                .get(Calendar.YEAR), curDate.get(Calendar.MONTH), curDate
                .get(Calendar.DATE) + 1, 0, 0, 0);
        int times = (int) (tommorowDate.getTimeInMillis() - curDate.getTimeInMillis()) / 1000;
        CookieUtil.setCrossCookieForTimes(Constants.FINISHED_PLUGIN_ID_KEY + consumerId, finishIds, times);
    }


    /***
     * @Description: getDsmFromReferer 从refreer中解出dsm
     *
     * @Param: [request]
     * @Return: java.lang.String
     * @throws:
     * @author: youhaijun
     * @Date: 2017/9/6
     */
    private String getDsmFromReferer(String referer) {
        Map<String, String> stringStringMap = UrlUtils.uRLRequest(referer);
        if (stringStringMap.isEmpty()) {
            return StringUtils.EMPTY;
        }
        String dsm = stringStringMap.get("dsm");
        return StringUtils.isBlank(dsm) ? "" : dsm;
    }

    @Override
    public List<ActivityPluginDto> selectAvailablePluginByIds(List<Long> ids) {
        if(CollectionUtils.isEmpty(ids)) {
            return Collections.emptyList();
        }
        DubboResult<List<ActivityPluginDto>> dr = this.remotePluginService.selectAvailablePluginByIds(ids);
        if (!dr.isSuccess()) {
            throw new ActivityRuntimeException(ErrorCode.E0400000);
        }
        return dr.getResult();
    }

}
