package cn.com.ctop.kuaishou.modules.ai.service.impl;

import cn.com.ctop.common.module.entity.CtopOauthToken;
import cn.com.ctop.common.module.entity.MaterialCutFrame;
import cn.com.ctop.common.module.service.ICtopOauthTokenService;
import cn.com.ctop.common.module.service.IMaterialCutFrameService;
import cn.com.ctop.common.module.utils.Check;
import cn.com.ctop.common.module.utils.HttpUtils;
import cn.com.ctop.common.module.utils.KuaishouInterfaceConstant;
import cn.com.ctop.common.module.utils.PropertiesUtils;
import cn.com.ctop.kuaishou.modules.ai.entity.*;
import cn.com.ctop.kuaishou.modules.ai.enums.KuaishouCreativeAdsenceTypeEnum;
import cn.com.ctop.kuaishou.modules.ai.enums.KuaishouProjectCreativeMatTypeEnum;
import cn.com.ctop.kuaishou.modules.ai.mapper.KuaishouVideoDirectionalPackageMapper;
import cn.com.ctop.kuaishou.modules.ai.service.*;
import cn.com.ctop.kuaishou.modules.batch.entity.KuaiShouAppList;
import cn.com.ctop.kuaishou.modules.batch.entity.KuaiShouCreative;
import cn.com.ctop.kuaishou.modules.batch.entity.KuaiShouImageGet;
import cn.com.ctop.kuaishou.modules.batch.entity.KuaiShouVideoGet;
import cn.com.ctop.kuaishou.modules.batch.service.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RedisUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
@Service
public class AiKuaishouProjectCreateCreativeServiceImpl implements IAiKuaishouProjectCreateCreativeService {
    @Autowired
    private IKuaiShouGroupTemplateService groupTemplateService;
    @Autowired
    private ICtopOauthTokenService tokenService;
    @Autowired
    private IKuaishouInterfaceService kuaishouInterfaceService;
    @Autowired
    private IKuaiShouVideoGetService videoGetService;
    @Autowired
    private IKuaishouProjectVideoGetService projectVideoGetService;
    @Autowired
    private IMaterialCutFrameService materialCutFrameService;
    @Autowired
    private IKuaiShouImageGetService imageGetService;
    @Autowired
    private IKuaiShouMaterialUploadService materialUploadService;
    @Autowired
    private IKuaishouAccountCreativeOverrunInfoService overrunInfoService;
    @Autowired
    private IAiKuaishouCampaignLevelOperationRecordService aiKuaishouCampaignLevelOperationRecordService;
    @Autowired
    private IAiKuaishouAccountLevelOperationRecordService kuaishouAccountLevelOperationRecordService;
    @Autowired
    private IAiKuaishouUnitLevelOperationRecordService unitLevelOperationRecordService;
    @Autowired
    private IAiKuaishouCreativeLevelOperationRecordService creativeLevelOperationRecordService;
    @Autowired
    private IAiKuaishouProgramCreativeLevelOperationRecordService kuaishouProgramCreativeLevelOperationRecordService;
    @Autowired
    private IKuaiShouAppMultipleBidsService kuaiShouAppMultipleBidsService;
    @Autowired
    private KuaishouVideoDirectionalPackageMapper packageMapper;
    @Autowired
    private IKuaishouAppPackageService appPackageService;
    @Autowired
    private IKuaishouDirectionalPackageService directionalPackageService;
    @Autowired
    private IKuaiShouCreativeService kuaiShouCreativeService;
    @Autowired
    private IKuaiShouUpdateService updateService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private IKuaiShouAppListService appListService;
    @Autowired
    private IKuaiShouCampaignService campaignService;
    @Autowired
    private IKuaiShouGroupService groupService;


    static ExecutorService executorService = Executors.newFixedThreadPool(2);

    /**
     * 检查匹配
     */
    @Override
    public void projectAutomaticCreates(KuaishouProjectStrategy strategy, Integer operationType) {
        try {
            Integer customUnitCnt = strategy.getCustomUnitCnt();
            if (Check.isNull(customUnitCnt)) {
                Integer imageCnt = strategy.getImageCnt();
                if (imageCnt <= 5) {
                    customUnitCnt = 600;
                } else {
                    customUnitCnt = 2000 / imageCnt;
                }
            }
            //程序化组数 最大60
            Integer programUnitCnt = strategy.getProgramUnitCnt();
            if (Check.isNull(programUnitCnt)) {
                Integer imageCnt = strategy.getImageCnt();
                if (imageCnt <= 5) {
                    programUnitCnt = 60;
                } else {
                    programUnitCnt = 300 / imageCnt;
                }
            }
            //创意制作方式，0-不限，4-自定义,7-程序化创意
            if (strategy.getUnitType() == 4) {
                this.autoCreateCreative(strategy, 1, customUnitCnt, 1);
            } else {
                this.autoCreateProgramCreative(strategy, 1, programUnitCnt, 1);
            }
        } catch (Exception e) {
            log.error("检查匹配异常", e);
        }
    }

    /**
     * 自定义补充
     */
    @Override
    public void customCreativeSupplement(KuaishouProjectStrategy strategy, Integer hour) throws ParseException {
        Integer customUnitCnt = strategy.getCustomUnitCnt();
        if (Check.isNull(customUnitCnt)) {
            Integer imageCnt = strategy.getImageCnt();
            if (imageCnt <= 5) {
                customUnitCnt = 600;
            } else {
                customUnitCnt = 2000 / imageCnt;
            }
        }
        int unitNum = customUnitCnt * hour / 20;
        log.info("{}当前时间内需要创建组总数：{}", strategy.getAccountId(), unitNum);
        //查询当前账户创建自定义类型组数量
        int unitCreateCnt = groupService.queryToDayBuiltCount(strategy.getAccountId(), 4);
        log.info("{}截止目前创建组总数：{}", strategy.getAccountId(), unitCreateCnt);
        int remindCnt = unitNum - unitCreateCnt;
        int concat = strategy.getSourceMaterial().contains("3") ? 3 : 0;
        if (concat != 0 && remindCnt >= 1) {
            log.info("{}组创建不足，剩余需要创建个数{},即将使用历史遗漏素材创建...", strategy.getAccountId(), remindCnt);
            //优先创建历史遗漏素材
            remindCnt = this.autoCreateCreative(strategy, 3, remindCnt, 2);
        }
        concat = strategy.getSourceMaterial().contains("2") ? 2 : 0;
        if (concat != 0 && remindCnt >= 1) {
            log.info("{}组创建不足，剩余需要创建个数{},正在使用高质量素材创建...", strategy.getAccountId(), remindCnt);
            //高质量素材
            remindCnt = this.autoCreateCreative(strategy, 2, remindCnt, 2);
        }
        concat = strategy.getSourceMaterial().contains("4") ? 4 : 0;
        if (concat != 0 && remindCnt >= 1) {
            //历史打捞素材
            log.info("{}组创建不足，剩余需要创建个数{},将要使用历史打捞素材创建...", strategy.getAccountId(), remindCnt);
            this.autoCreateCreative(strategy, 4, remindCnt, 2);
        }
    }

    /**
     * 自定义上新
     */
    @Override
    public void projectAutomaticCreates(KuaishouProjectStrategy strategy) {
        try {
            Integer customUnitCnt = strategy.getCustomUnitCnt();
            if (Check.isNull(customUnitCnt)) {
                Integer imageCnt = strategy.getImageCnt();
                if (imageCnt <= 5) {
                    customUnitCnt = 600;
                } else {
                    customUnitCnt = 2000 / imageCnt;
                }
            }
            log.info("{}可创建组总数：{}", strategy.getAccountId(), customUnitCnt);
            //查询当前账户创建自定义类型组数量
            int unitCreateCnt = groupService.queryToDayBuiltCount(strategy.getAccountId(), 4);
            if(Check.isNull(unitCreateCnt)){
                unitCreateCnt = 0;
            }
            log.info("{}截止目前创建组总数：{}", strategy.getAccountId(), unitCreateCnt);
            int remindCnt = customUnitCnt - unitCreateCnt;
            if (remindCnt >= 1) {
                this.autoCreateCreative(strategy, 1, remindCnt, 2);
            }
        } catch (Exception e) {
            log.error("项目自动创建自定义上新异常", e);
        }
    }

    /**
     * 程序化上新
     */
    @Override
    public void projectProgramAutomaticCreates(KuaishouProjectStrategy strategy, Integer type) {
        try {
            Integer programUnitCnt = strategy.getProgramUnitCnt();
            if (Check.isNull(programUnitCnt)) {
                Integer imageCnt = strategy.getImageCnt();
                if (imageCnt <= 5) {
                    programUnitCnt = 60;
                } else {
                    programUnitCnt = 300 / imageCnt;
                }
            }
            this.autoCreateProgramCreative(strategy, type, programUnitCnt, 2);
        } catch (Exception e) {
            log.error("项目自动创建程序化上新异常", e);
        }
    }


    /**
     * 创建自定义创意
     *
     * @param strategy   账户配置信息
     * @param createType 创意创建类型 1:素材上新 2：历史高质量 3:历史遗漏素材 4:历史打捞
     * @param videoCnt   视频数量
     */
    private Integer autoCreateCreative(KuaishouProjectStrategy strategy, Integer createType, Integer videoCnt, Integer operationType) {
        try {
            String strategyUuid = UUID.randomUUID().toString();
            strategy.setStrategyUuid(strategyUuid);
            strategy.setUnitType(4);
            Long accountId = strategy.getAccountId();
            CtopOauthToken token = tokenService.getOauthTokenByAccountId(accountId.toString());
            if (null == token) {
                log.info("token获取失败=>accountId:{}", accountId);
                insertAccountOperationRecord(strategy, "获取token失败", operationType, 0);
                return videoCnt;
            }
            //1:获取账户视频信息
            kuaishouInterfaceService.getVideoList(token, DateUtils.date2Str(), DateUtils.date2Str());
            //2:同步项目视频信息
            projectVideoGetService.clearProjectVideo(strategy.getProjectId(), 1, null);
            Long timeStart = KuaishouProjectCreativeMatTypeEnum.getStartTimeByType(strategy.getUnitType().toString() + createType.toString());
            Long timeEnd = KuaishouProjectCreativeMatTypeEnum.getEndTimeByType(strategy.getUnitType().toString() + createType.toString());
            Long now = System.currentTimeMillis();
            String startTime = DateUtils.formatDateTime(now + timeStart * 60 * 1000L);
            String endTime = DateUtils.formatDateTime(now + timeEnd * 60 * 1000L);

            Integer singleAppid = strategy.getSingleAppid();
            //单/多应用，1单应用，2多应用
            if (null != singleAppid && singleAppid == 1) {
                //单一应用
                String replaceString = KuaishouProjectCreativeMatTypeEnum.getNameByType(strategy.getUnitType().toString() + createType.toString());
                List<KuaiShouVideoGet> newVideoList = getVideosByParams(strategy, startTime, endTime, null, createType, Long.valueOf(videoCnt));
                if (null == newVideoList || newVideoList.isEmpty()) {
                    log.info("自定义创建(账户：{})，{} 到 {} 未获取到相应素材({})", accountId, startTime, endTime, replaceString);
                    return videoCnt;
                }
                //根据素材可用日期过滤
                List<KuaiShouVideoGet> newVideos = new ArrayList<>();
                for (KuaiShouVideoGet newVideo : newVideoList) {
                    if (!Check.isNull(newVideo.getPutEndTime()) && !Check.isNull(newVideo.getPutStartTime())) {
                        boolean b = DateUtils.checkTimeLimit(new Date(), DateUtils.parseDate(newVideo.getPutStartTime() + " 00:00:01", "yyyy-MM-dd HH:mm:ss"), DateUtils.parseDate(newVideo.getPutEndTime() + " 23:59:59", "yyyy-MM-dd HH:mm:ss"));
                        if (b) {
                            newVideos.add(newVideo);
                        }
                    } else {
                        newVideos.add(newVideo);
                    }
                }
                if (newVideos.size() == 0) {
                    log.info("自定义创建(账户：{})，{} 到 {} 未获取到达标素材({})", accountId, startTime, endTime, replaceString);
                    return videoCnt;
                }
                Long appId = null;
                //appId，当计划类型为2时必填
                if (strategy.getCampaignType() == 2 || strategy.getCampaignType() == 7) {
                    Long appTemId = Check.isNull(strategy.getAppId()) ? JSONArray.parseArray(strategy.getAppIdArray()).getLong(0) : strategy.getAppId();
                    if (Check.isNull(appTemId)) {
                        insertAccountOperationRecord(strategy, "未获取到项目应用模板", operationType, 0);
                        return videoCnt;
                    }
                    JSONObject app = appPackageService.queryAppId(appTemId, token.getAccountId());
                    if (Check.isNull(app) || Check.isNull(app.getLong("app_id"))) {
                        insertAccountOperationRecord(strategy, "未获取到appId", operationType, 0);
                        return videoCnt;
                    }
                    appId = app.getLong("app_id");
                    strategy.setClickTrackUrl(app.getString("track_url"));
                    strategy.setImpressionUrl(app.getString("impression_url"));
                    strategy.setAdPhotoPlayedT3sUrl(app.getString("ad_photo_played_t3s_url"));
                    strategy.setActionbarClickUrl(app.getString("actionbar_click_url"));
                }
                Long newCampaignId = getCampaignId(strategy, token, replaceString, "TODAY", createType, appId, strategyUuid);
                if (null == newCampaignId) {
                    insertAccountOperationRecord(strategy, "创建广告计划失败", operationType, 0);
                    return videoCnt;
                }
                strategy.setCampaignId(newCampaignId);
                //3、在“上新”计划中新增广告组，一个素材搭配n张封面，组成一个广告组
                for (KuaiShouVideoGet videoItem : newVideos) {
                    Boolean unitOverrun = getUnitOverrun(accountId.toString());
                    if (unitOverrun) {
                        log.error("组创建超限,accountId:{}", accountId);
                        return 0;
                    }
                    //快手账户创意创建超限记录信息，查到数据则说明已经超限
                    KuaishouAccountCreativeOverrunInfo overrunInfo = overrunInfoService.getByParams(accountId, DateUtils.formatDate(new Date()));
                    if (null != overrunInfo) {
                        return 0;
                    }
                    // 每个组，搭配5个创意
                    List<MaterialCutFrame> cutFrameList = materialCutFrameService.getListByVideoSignature(videoItem.getSignature());
                    if ((null == cutFrameList || cutFrameList.isEmpty())) {
                        log.info("未获取到视频封面=>videoSignature:{}", videoItem.getSignature());
                        continue;
                    }
                    JSONObject unitParams = createUnitParams(token, newCampaignId, strategy, appId, videoItem, operationType);
                    if (!Check.isNull(unitParams) && operationType == 2) {
                        String unitName = getName(strategy.getGroupName(), strategy, createType, videoItem.getPhotoName(), "unit", newCampaignId, appId, videoItem.getMaterialType());
                        unitParams.put("unit_name", unitName);
                        AiKuaishouUnitLevelOperationRecord unitLevelOperationRecord = new AiKuaishouUnitLevelOperationRecord();
                        BeanUtils.copyProperties(strategy, unitLevelOperationRecord);
                        unitLevelOperationRecord.setGroupName(unitName);
                        unitLevelOperationRecord.setCampaignId(newCampaignId);
                        unitLevelOperationRecord.setCpaBid(unitParams.getInteger("cpa_bid"));
                        unitLevelOperationRecord.setBid(unitParams.getInteger("bid"));
                        unitLevelOperationRecord.setDeepConversionBid(unitParams.getInteger("deep_conversion_bid"));
                        unitLevelOperationRecord.setCreateTime(new Date());
                        unitLevelOperationRecord.setCampaignId(newCampaignId);
                        unitLevelOperationRecord.setAiStrategyUuid(strategyUuid);
                        unitLevelOperationRecord.setCreateType(2);//项目创建
                        Integer unitCode = -1;
                        String msg = unitParams.getString("errorMsg");
                        String nowDate = DateUtils.formatDate(new Date(), "yy-MMdd");
                        String redisKey = strategy.getAccountId() + "_" + newCampaignId + nowDate;
                        Integer redisValue = (Integer) redisUtil.get(redisKey);
                        if (Check.isNull(msg)) {
                            Map<String, Object> unitCreateResult = kuaishouInterfaceService.adUnitCreate(token.getAccessToken(), token.getAccountId(), unitParams, 1);
                            unitCode = (Integer) unitCreateResult.get("code");
                            msg = (String) unitCreateResult.get("message");
                            unitLevelOperationRecord.setStatus(unitCode);
                            unitLevelOperationRecord.setMessage(msg);
                            if (unitCode == 0) {
                                Long unitId = (Long) unitCreateResult.get("unitId");
                                log.info("(accountId:{})创建自定义组({}).....success....", accountId, unitId);
                                unitLevelOperationRecord.setUnitId(unitId);
                                unitLevelOperationRecordService.saveOrUpdate(unitLevelOperationRecord);
                                videoCnt--;
                                JSONObject creativeParams = creativeParams(token, unitId, videoItem, strategy);
                                createCreativeByImage(cutFrameList, token, creativeParams, newCampaignId, unitId, videoItem, strategy.getImageCnt(), strategy, strategyUuid, null);
                            } else {
                                log.info("(accountId:{})创建自定义组.....fail....{}", accountId, msg);
                                unitLevelOperationRecordService.saveOrUpdate(unitLevelOperationRecord);
                                redisUtil.set(redisKey, redisValue - 1, 100000L);
                            }
                        } else {
                            log.info("(accountId:{})创建自定义组.....fail....{}", accountId, msg);
                            unitLevelOperationRecord.setStatus(unitCode);
                            unitLevelOperationRecord.setMessage(msg);
                            unitLevelOperationRecordService.saveOrUpdate(unitLevelOperationRecord);
                            redisUtil.set(redisKey, redisValue - 1, 100000L);
                        }
                        if (videoCnt <= 0) {
                            return videoCnt;
                        }
                    }
                }
            }
        } catch (
                BeansException e) {
            log.error("创建自定义创意异常", e);
            insertAccountOperationRecord(strategy, "创建自定义创意异常", operationType, 0);
        }

        insertAccountOperationRecord(strategy, "success", operationType, 1);
        return videoCnt;
    }

    /**
     * 创建程序化创意
     *
     * @param strategy
     */
    public void autoCreateProgramCreative(KuaishouProjectStrategy strategy, Integer createType, Integer videoCnt, Integer operationType) {
        try {
            String strategyUuid = UUID.randomUUID().toString();
            strategy.setStrategyUuid(strategyUuid);
            strategy.setUnitType(7);
            Long accountId = strategy.getAccountId();
            CtopOauthToken token = tokenService.getOauthTokenByAccountId(accountId.toString());
            if (null == token) {
                log.info("token获取失败=>accountId:{}", accountId);
                insertAccountOperationRecord(strategy, "token获取失败", operationType, 0);
                return;
            }
            //1:获取视频信息
            kuaishouInterfaceService.getVideoList(token, DateUtils.date2Str(), DateUtils.date2Str());
            //2:同步项目视频信息
            projectVideoGetService.clearProjectVideo(strategy.getProjectId(), 1, null);
            //3:判定账户是否单一应用
            Long timeStart = null;
            Long timeEnd = null;
            Integer singleAppid = strategy.getSingleAppid();
            if (null != singleAppid && singleAppid == 1) {
                timeStart = -7 * 60 * 24L;
                timeEnd = -5L;
            } else {
                timeStart = KuaishouProjectCreativeMatTypeEnum.getStartTimeByType(strategy.getUnitType().toString() + createType.toString());
                timeEnd = KuaishouProjectCreativeMatTypeEnum.getEndTimeByType(strategy.getUnitType().toString() + createType.toString());
            }
            Long now = System.currentTimeMillis();
            String startTime = DateUtils.formatDateTime(now + timeStart * 60 * 1000L);
            String endTime = DateUtils.formatDateTime(now + timeEnd * 60 * 1000L);
            String nowDate = DateUtils.getNowDate("yyyy-MM-dd");
            String key = token.getAccountId() + "_ProgramCreative" + "_" + nowDate;

            //单/多应用，1单应用，2多应用
            if (null != singleAppid && singleAppid == 1) {
                String replaceString = KuaishouProjectCreativeMatTypeEnum.getNameByType(strategy.getUnitType().toString() + createType.toString());
                //单一应用
                List<KuaiShouVideoGet> allVideoList = getVideosByParams(strategy, startTime, endTime, null, createType, Long.valueOf(videoCnt));
                if (null == allVideoList) {
                    log.info("程序化账户：{}，{} 到 {} 时间段内未获取到相应素材({})", accountId, startTime, endTime, replaceString);
//                    insertAccountOperationRecord(strategy, "账户在" + startTime + "~" + endTime + "时间段内未获取到相应素材(" + replaceString + ")", operationType, 0);
                    return;
                }
                //根据素材可用日期过滤
                List<KuaiShouVideoGet> allVideos = new ArrayList<>();
                for (KuaiShouVideoGet newVideo : allVideoList) {
                    if (!Check.isNull(newVideo.getPutEndTime()) && !Check.isNull(newVideo.getPutStartTime())) {
                        boolean b = DateUtils.checkTimeLimit(new Date(), DateUtils.parseDate(newVideo.getPutStartTime() + " 00:00:01", "yyyy-MM-dd HH:mm:ss"), DateUtils.parseDate(newVideo.getPutEndTime() + " 23:59:59", "yyyy-MM-dd HH:mm:ss"));
                        if (b) {
                            allVideos.add(newVideo);
                        }
                    } else {
                        allVideos.add(newVideo);
                    }
                }
                if (allVideos.size() == 0) {
                    log.info("程序化账户：{}，{} 到 {} 未获取到达标素材({})", accountId, startTime, endTime, replaceString);
                    return;
                }

                Long appId = null;
                //appId，当计划类型为2时必填
                if (strategy.getCampaignType() == 2 || strategy.getCampaignType() == 7) {
                    Long appTemId = Check.isNull(strategy.getAppId()) ? JSONArray.parseArray(strategy.getAppIdArray()).getLong(0) : strategy.getAppId();
                    if (Check.isNull(appTemId)) {
                        insertAccountOperationRecord(strategy, "未获取到项t目应用模板", operationType, 0);
                        return;
                    }
                    JSONObject app = appPackageService.queryAppId(appTemId, token.getAccountId());
                    if (Check.isNull(app) || Check.isNull(app.getLong("app_id"))) {
                        insertAccountOperationRecord(strategy, "未获取到appId", operationType, 0);
                        return;
                    }
                    appId = app.getLong("app_id");
                    strategy.setClickTrackUrl(app.getString("track_url"));
                    strategy.setImpressionUrl(app.getString("impression_url"));
                    strategy.setAdPhotoPlayedT3sUrl(app.getString("ad_photo_played_t3s_url"));
                    strategy.setActionbarClickUrl(app.getString("actionbar_click_url"));
                }
                Long newCampaignId = getCampaignId(strategy, token, replaceString, "TODAY", createType, appId, strategyUuid);
                if (null == newCampaignId) {
                    insertAccountOperationRecord(strategy, "创建广告计划失败", operationType, 0);
                    return;
                }
                strategy.setCampaignId(newCampaignId);
                //创意
                List<List<KuaiShouVideoGet>> splitVideos = Lists.partition(allVideos, strategy.getImageCnt());
                for (int j = 1; j < splitVideos.size() + 1; j++) {
                    Boolean unitOverrun = getUnitOverrun(accountId.toString());
                    if (unitOverrun) {
                        log.error("组创建超限,accountId:{}", accountId);
                        return;
                    }

                    Object redisObj = redisUtil.get(key);
                    if (!Check.isNull(redisObj)) {
                        Integer value = (Integer) redisObj;
                        if (value == 1) {
                            log.error("程序化创意创建超限,accountId:{}", strategy.getAccountId());
                            return;
                        }
                    }
                    //创建组
                    JSONObject unitParams = createUnitParams(token, newCampaignId, strategy, appId, null, operationType);
                    if (!Check.isNull(unitParams) && operationType == 2) {
                        String unitName = getName(strategy.getGroupName(), strategy, createType, null, "unit", newCampaignId, appId, null);
                        unitParams.put("unit_name", unitName);
                        AiKuaishouUnitLevelOperationRecord unitLevelOperationRecord = new AiKuaishouUnitLevelOperationRecord();
                        BeanUtils.copyProperties(strategy, unitLevelOperationRecord);
                        unitLevelOperationRecord.setGroupName(unitName);
                        unitLevelOperationRecord.setCampaignId(newCampaignId);
                        unitLevelOperationRecord.setCpaBid(unitParams.getInteger("cpa_bid"));
                        unitLevelOperationRecord.setBid(unitParams.getInteger("bid"));
                        unitLevelOperationRecord.setDeepConversionBid(unitParams.getInteger("deep_conversion_bid"));
                        unitLevelOperationRecord.setCreateTime(new Date());
                        unitLevelOperationRecord.setCampaignId(newCampaignId);
                        unitLevelOperationRecord.setAiStrategyUuid(strategyUuid);
                        unitLevelOperationRecord.setCreateType(2);//项目创建
                        Integer unitCode = -1;
                        String errorMsg = unitParams.getString("errorMsg");
                        String redisKey = strategy.getAccountId() + "_" + newCampaignId + DateUtils.formatDate(new Date(), "yy-MMdd");
                        Integer redisValue = (Integer) redisUtil.get(redisKey);
                        if (Check.isNull(errorMsg)) {
                            log.info("创建广告组入参：{}", unitParams);
                            Map<String, Object> unitCreateResult = kuaishouInterfaceService.adUnitCreate(token.getAccessToken(), token.getAccountId(), unitParams, 1);
                            unitCode = (Integer) unitCreateResult.get("code");
                            errorMsg = (String) unitCreateResult.get("message");
                            unitLevelOperationRecord.setStatus(unitCode);
                            unitLevelOperationRecord.setMessage(errorMsg);
                            if (unitCode == 0) {
                                Long unitId = (Long) unitCreateResult.get("unitId");
                                log.info(".........程序化组创建成功 =>accountId:{};unitId:{}", accountId, unitId);
                                unitLevelOperationRecord.setUnitId(unitId);
                                unitLevelOperationRecordService.saveOrUpdate(unitLevelOperationRecord);
                                JSONObject creativeParams = programCreativeParams(token, unitId, splitVideos.get(j - 1), strategy, j, null);
                                createProgramCreative(token, creativeParams, strategy);
                            } else {
                                log.info(".........程序化组创建失败=>accountId:{};message:{}", accountId, errorMsg);
                                unitLevelOperationRecordService.saveOrUpdate(unitLevelOperationRecord);
                                redisUtil.set(redisKey, redisValue - 1, 100000L);
                            }
                        } else {
                            log.info(".........程序化组创建失败=>accountId:{};message:{}", accountId, errorMsg);
                            unitLevelOperationRecord.setStatus(unitCode);
                            unitLevelOperationRecord.setMessage(errorMsg);
                            unitLevelOperationRecordService.saveOrUpdate(unitLevelOperationRecord);
                            redisUtil.set(redisKey, redisValue - 1, 100000L);
                        }
                    }
                }
            }
        } catch (BeansException e) {
            e.printStackTrace();
            log.error("创建程序化创意异常", e);
        }
        insertAccountOperationRecord(strategy, "success", operationType, 1);
    }

    private void createProgramCreative(CtopOauthToken token, JSONObject creativeParams, KuaishouProjectStrategy strategy) {
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put("Access-Token", token.getAccessToken());
        String url = PropertiesUtils.getConfig("kuaishou_api_url") + KuaishouInterfaceConstant.PROGRAM_CREATE;
        String result = HttpUtils.kuaiShouhttpPostRequest(url, creativeParams.toJSONString(), headers);
        JSONObject resultJson = JSON.parseObject(result);
        log.info("创建程序化创意返回结果：{}", resultJson);
        if (Check.isNull(resultJson)) {
            log.error("程序化创意创意异常：api接口返回为空");
            return;
        }
        Integer code = resultJson.getInteger("code");
        String message = resultJson.getString("message");
        Long unitId = creativeParams.getLong("unit_id");
        //添加程序化创意和添加记录
        insertCreativeAndRecord(creativeParams, resultJson, strategy);
        if (code == 0) {
            log.info("创建程序化创意成功，accountId：{}，unit：{}", token.getAccountId(), unitId);
        } else {
            log.error("快手创建程序化创意失败，accountId:{},unitId:{}，返回信息:{}", token.getAccountId(), unitId, message);
            if (code == 400001 && "/rest/openapi/v2/creative/advanced/program/create调用已超日限，次日可恢复调用".equals(message)) {
                String nowDate = DateUtils.getNowDate("yyyy-MM-dd");
                String key = token.getAccountId() + "_ProgramCreative" + "_" + nowDate;
                redisUtil.set(key, 1, 100000L);
                updateService.updateUnitStatus(token.getAccessToken(), token.getAccountId(), unitId, 3, "e9ca23d68d884d4ebb19d07889727dae");
            }
        }
    }

    //添加程序化创意和添加记录
    private void insertCreativeAndRecord(JSONObject programJson, JSONObject resultJson, KuaishouProjectStrategy strategy) {
        Integer code = resultJson.getInteger("code");
        String message = resultJson.getString("message");
        if (code == 0) {
            JSONObject data = resultJson.getJSONObject("data");
            KuaiShouCreative kuaiShouCreative = JSONObject.parseObject(programJson.toJSONString(), KuaiShouCreative.class);
            BeanUtils.copyProperties(strategy, kuaiShouCreative);
            kuaiShouCreative.setCreativeId(-1L);
            kuaiShouCreative.setUnitId(data.getLong("unit_id"));
            kuaiShouCreativeService.save(kuaiShouCreative);
        }
        AiKuaishouProgramCreativeLevelOperationRecord record = JSONObject.parseObject(programJson.toJSONString(), AiKuaishouProgramCreativeLevelOperationRecord.class);
        BeanUtils.copyProperties(strategy, record);
        record.setStatus(code);
        record.setAccountId(strategy.getAccountId());
        record.setAiStrategyUuid(strategy.getStrategyUuid());
        record.setMessage(message);
        record.setOperationType(1);
        record.setCreateTime(new Date());
        record.setCreateType(2);//项目自动投放
        kuaishouProgramCreativeLevelOperationRecordService.saveOrUpdate(record);
    }

    private void createProgramCreative(CtopOauthToken token, JSONObject creativeParams, Long campaignId, Long unitId,
                                       int creativeCnt, KuaiShouVideoGet videoGet, KuaishouProjectStrategy strategy, String uuid, String appVersion) {
        String creativeName = null;
        if (!Check.isNull(appVersion)) {
            creativeName = appVersion + "_" + creativeCnt;
        } else {
            creativeName = "自定义创意_" + creativeCnt;
        }
        creativeParams.put("creative_name", creativeName);
        Map<String, Object> creativeCreateResult = kuaishouInterfaceService.creativeCreate(token.getAccessToken(), token.getAccountId(), creativeParams, 1);
        Integer creativeCode = (Integer) creativeCreateResult.get("code");
        String creativeMessage = (String) creativeCreateResult.get("message");

        if (creativeCode == -1 && "/rest/openapi/v2/creative/create调用已超日限，次日可恢复调用".equals(creativeMessage)) {
            updateService.updateUnitStatus(token.getAccessToken(), token.getAccountId(), unitId, 3, "e9ca23d68d884d4ebb19d07889727dae");
        } else if (creativeCode == -1 && creativeMessage.contains("超过可关联的有效创意的上限")) {
            updateService.updateUnitStatus(token.getAccessToken(), token.getAccountId(), unitId, 3, "e9ca23d68d884d4ebb19d07889727dae");
        } else if (creativeCode == -1 && creativeMessage.contains("视频不存在")) {
            updateService.updateUnitStatus(token.getAccessToken(), token.getAccountId(), unitId, 3, "e9ca23d68d884d4ebb19d07889727dae");
        }
    }

    private JSONObject programCreativeParams(CtopOauthToken token, Long unitId, List<KuaiShouVideoGet> list, KuaishouProjectStrategy strategy, Integer creativeCnt, String appVersion) {
        JSONObject programJson = new JSONObject();
        programJson.put("advertiser_id", token.getAccountId());
        programJson.put("unit_id", unitId);
        if (strategy.getSingleAppid() != null && strategy.getSingleAppid() == 1) {  // 多应用情况下 创意名称已app-versionMI命名
            if (!Check.isNull(appVersion)) {
                programJson.put("package_name", appVersion);
            } else {
                programJson.put("package_name", "程序化创意" + creativeCnt);
            }
        } else {
            programJson.put("package_name", "程序化创意" + creativeCnt);
        }
        JSONArray horizontalPhotoIds = new JSONArray();
        JSONArray verticalPhotoIds = new JSONArray();
        JSONArray coverImageTokens = new JSONArray();
        for (KuaiShouVideoGet videoGet : list) {
            List<MaterialCutFrame> cutFrameList = materialCutFrameService.getListByVideoSignature(videoGet.getSignature());
            if (!Check.isNull(cutFrameList)) {
                MaterialCutFrame cutFrame = cutFrameList.get(0);
                String imageToken = getImageToken(cutFrame.getUrl(), cutFrame.getSignature(), token.getAccountId(), token.getAccessToken());
                if (!Check.isNull(imageToken)) {
                    coverImageTokens.add(imageToken);
                }
            }
            if (videoGet.getMaterialType() == 2) {
                horizontalPhotoIds.add(videoGet.getPhotoId());
            }
            if (videoGet.getMaterialType() == 1) {
                verticalPhotoIds.add(videoGet.getPhotoId());
            }
        }
        programJson.put("horizontal_photo_ids", horizontalPhotoIds);
        programJson.put("vertical_photo_ids", verticalPhotoIds);
        if (coverImageTokens.size() >= 5) {
            coverImageTokens.remove(0);
        }
        programJson.put("cover_image_tokens", coverImageTokens);

        if (!Check.isNull(strategy.getSiteId())) {
            programJson.put("site_id", strategy.getSiteId());
        }
        if (!Check.isNull(strategy.getStickerTitle())) {
            programJson.put("sticker_styles", strategy.getStickerTitle());
        }

        if (!Check.isNull(strategy.getActionBarText())) {
            programJson.put("action_bar", getActionBar(strategy.getActionBarText()));
        }
        if (!Check.isNull(strategy.getClickTrackUrl())) {
            programJson.put("click_url", strategy.getClickTrackUrl());
        }
        if (!Check.isNull(strategy.getActionbarClickUrl())) {
            programJson.put("actionbar_click_url", strategy.getActionbarClickUrl());
        }

        JSONArray captions = getCaptions(strategy.getDescription());
        programJson.put("captions", captions);
        if (!Check.isNull(strategy.getCreativeCategory())) {
            programJson.put("creative_category", strategy.getCreativeCategory());
            programJson.put("creative_tag", JSON.parseArray(strategy.getCreativeTag()));
        }
        return programJson;
    }

    private JSONArray getCaptions(String description) {
        JSONArray jsonArray = JSONArray.parseArray(description);
        if (jsonArray.size() <= 3) {
            return jsonArray;
        }
        Collections.shuffle(jsonArray);
        JSONArray captions = new JSONArray();
        for (int i = 0; i < jsonArray.size(); i++) {
            captions.add(jsonArray.getString(i));
            if (captions.size() == 3) {
                break;
            }
        }
        return captions;
    }

    private List<KuaiShouVideoGet> getNewVideoListByParams(KuaishouProjectStrategy strategy, String startTime, String endTime, AiKuaiShouAppInfo appInfo) {
        if (null == appInfo) {
            Integer channelType = strategy.getChannelType() == 2 ? null : strategy.getChannelType();
            return projectVideoGetService.getNewVideoBetweenTime(strategy.getAccountId(), startTime, endTime, channelType);
        } else {
            //查询通用素材
            List<KuaiShouVideoGet> generalVideos = new ArrayList<>();
            List<KuaiShouVideoGet> customVideos = new ArrayList<>();

            customVideos = videoGetService.getNewVideoBetweenTime(strategy.getAccountId(), startTime, endTime, strategy.getChannelType(), "all", null);
            //2:查询特定素材
            generalVideos = videoGetService.getNewVideoBetweenTime(strategy.getAccountId(), startTime, endTime, strategy.getChannelType(), appInfo.getAppVersion(), null);
            if (Check.isNull(generalVideos) && Check.isNull(customVideos)) {
                log.info("账户：{}，appId({}){}到{}这段时间没有上新素材", strategy.getAccountId(), appInfo.getAppId(), startTime, endTime);
                return new ArrayList<>();
            }
            //合并
            if (null == generalVideos || generalVideos.isEmpty()) {
                return customVideos;
            } else if (null == customVideos || customVideos.isEmpty()) {
                return generalVideos;
            } else {
                generalVideos.addAll(customVideos);
                return generalVideos;
            }
        }
    }

    private List<KuaiShouVideoGet> getRelateZeroVideoList(KuaishouProjectStrategy strategy, String startTime, String endTime, AiKuaiShouAppInfo appInfo, Integer relativeCnt, Long videoCnt) {
        Integer channelType = null;
        String appVersion = Check.isNull(appInfo) ? "" : appInfo.getAppVersion();
        if (null != strategy.getChannelType() && strategy.getChannelType() != 2) {
            channelType = strategy.getChannelType();
        }
        return projectVideoGetService.getZeroVideoByParams(strategy.getAccountId(), startTime, endTime, videoCnt, appVersion, channelType, relativeCnt);
    }

    private List<KuaiShouVideoGet> getHistoryTopVideoListByParams(KuaishouProjectStrategy strategy, String startTime, String endTime, AiKuaiShouAppInfo appInfo, Long videoCnt) {
        Integer channelType = null;
        String appVersion = Check.isNull(appInfo) ? "" : appInfo.getAppVersion();
        if (null != strategy.getChannelType() && strategy.getChannelType() != 2) {
            channelType = strategy.getChannelType();
        }
        return projectVideoGetService.getHistoryTopVideoByParams(strategy.getAccountId(), startTime, endTime, videoCnt, appVersion, channelType);
    }

    /**
     * 创建自定义创意
     *
     * @param strategy   账户配置信息
     * @param createType 创意创建类型 1:素材上新 2：历史高质量 3:历史遗漏素材 4：历史素材打捞
     * @param startTime  开始时间
     * @param endTime    结束时间
     */
    private List<KuaiShouVideoGet> getVideosByParams(KuaishouProjectStrategy strategy, String startTime, String endTime, AiKuaiShouAppInfo appInfo, Integer createType, Long videoCnt) {
        try {
            if (createType == 1) {
                return getNewVideoListByParams(strategy, startTime, endTime, appInfo);
            } else if (createType == 2) {
                return getHistoryTopVideoListByParams(strategy, startTime, endTime, appInfo, videoCnt);
            } else if (createType == 3) {
                return getRelateZeroVideoList(strategy, startTime, endTime, appInfo, 0, videoCnt);
            } else {  //  type == 4 历史素材打捞
                return getRelateZeroVideoList(strategy, startTime, endTime, appInfo, 20, videoCnt);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获取素材异常", e);
        }
        return null;
    }


    private Long getCampaignId(KuaishouProjectStrategy strategy, CtopOauthToken token, String replaceString, String checkType, Integer createType, Long appId, String uuid) {
        Long campaignId = null;
        try {
            campaignId = null;
            if ("ALL_CAMPAIGN".equals(checkType)) {
                campaignId = campaignService.getCampaignIdByAccountAndName(strategy.getAccountId(), replaceString);
            } else if ("TODAY".equals(checkType)) {
                //查询当天创建的计划
                String nowDate = DateUtils.getNowDate("yyyy-MM-dd") + " 00:00:01";
                campaignId = campaignService.getCampaignIdByAccountAndNameAndDate(strategy.getAccountId(), replaceString, nowDate);
            }
            if (!Check.isNull(campaignId)) {
                return campaignId;
            }

            // 不存在“上新”计划，则创建一个计划
            JSONObject campaignParams = new JSONObject();
            campaignParams.put("advertiser_id", token.getAccountId());
            String campaignName = getName(strategy.getCampaignName(), strategy, createType, null, "plan", null, appId, null);
            campaignParams.put("campaign_name", campaignName);
            campaignParams.put("type", strategy.getCampaignType());
            if (null != strategy.getCampaignDayBudget() && strategy.getCampaignDayBudget() != 0) {
                campaignParams.put("day_budget", strategy.getCampaignDayBudget());
            }
            Map<String, Object> campaignCreateResult = kuaishouInterfaceService.campaignCreate(token.getAccessToken(), token.getAccountId(), campaignParams);
            Integer code = (Integer) campaignCreateResult.get("code");
            String message = (String) campaignCreateResult.get("message");
            AiKuaishouCampaignLevelOperationRecord record = new AiKuaishouCampaignLevelOperationRecord(strategy, null, code, message);
            record.setAiStrategyUuid(uuid);
            record.setCampaignName(campaignName);
            record.setCreateType(2);//项目创建

            if (code != 0) {
                log.info("计划创建失败=>message:{}", message);
                record.setCampaignId(0L);
                aiKuaishouCampaignLevelOperationRecordService.saveOrUpdate(record);
                return null;
            }

            campaignId = (Long) campaignCreateResult.get("campaignId");
            record.setCampaignId(campaignId);
            aiKuaishouCampaignLevelOperationRecordService.saveOrUpdate(record);
            Integer campaignStatus = strategy.getCampaignStatus();
            if (!Check.isNull(campaignStatus) && campaignStatus == 2) {
                updateService.updateCampaignStatus(token.getAccessToken(), token.getAccountId(), campaignId, campaignStatus, "yumeng");
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获取广告计划异常", e);
        }
        return campaignId;
    }

    private JSONObject createUnitParams(CtopOauthToken token, Long campaignId, KuaishouProjectStrategy strategy, Long appId, KuaiShouVideoGet videoItem, Integer operationType) {
        JSONObject unitParams = null;
        try {
            // 拼装创建组的入参 json
            unitParams = new JSONObject();
            Integer unitType = strategy.getUnitType();
            //创意制作方式
            unitParams.put("unit_type", unitType);
            unitParams.put("advertiser_id", token.getAccountId());
            unitParams.put("campaign_id", campaignId);
            //出价类型
            unitParams.put("bid_type", strategy.getBidType());
            if (!Check.isNull(strategy.getGroupStatus()) && strategy.getGroupStatus() == 2) {
                unitParams.put("put_status", strategy.getGroupStatus());
            }

            //组单日预算
            if (null != strategy.getUnitDayBudget() && strategy.getUnitDayBudget() != 0) {
                unitParams.put("day_budget", strategy.getUnitDayBudget());
            } else {
                unitParams.put("day_budget", 0);
            }
            //应用商店列表
            unitParams.put("ocpx_action_type", strategy.getOcpxActionType());
            //出价
            if (!Check.isNull(strategy.getBid()) && !"0".equals(strategy.getBid())) {
                Long bid = getBidByString(strategy.getBid());
                unitParams.put("bid", bid);
            }
            if (!Check.isNull(strategy.getCpaBid()) && !"0".equals((strategy.getCpaBid()))) {
                Long cpdBid = getBidByString(strategy.getCpaBid());
                unitParams.put("cpa_bid", cpdBid);
            }
            //优先低成本
            if (null != strategy.getSmartBid() && strategy.getSmartBid() != 0) {
                unitParams.put("smart_bid", strategy.getSmartBid());
            }
            //优化目标
            if (!Check.isNull(strategy.getOcpxActionType())) {
                unitParams.put("ocpx_action_type", strategy.getOcpxActionType());
            }
            //深度转化目标
            if (!Check.isNull(strategy.getDeepConversionType())) {
                unitParams.put("deep_conversion_type", strategy.getDeepConversionType());
            }
            //付费ROI系数
            if (!Check.isNull(strategy.getRoiRatio())) {
                unitParams.put("roi_ratio", strategy.getRoiRatio());
            }
            //深度转化目标出价
            if (!Check.isNull(strategy.getDeepConversionBid())) {
                Long deepConversionBid = getBidByString(strategy.getDeepConversionBid());
                unitParams.put("deep_conversion_bid", deepConversionBid);
            }
            Integer sceneId = null;
            String scenceIdString = strategy.getSceneId();

            if (!Check.isNull(scenceIdString) && !Check.isNull(JSON.parseArray(scenceIdString))) {
                JSONArray scenceArray = JSON.parseArray(scenceIdString);
                sceneId = scenceArray.getInteger(0);
                unitParams.put("scene_id", scenceArray);
            }
            Integer campaignType = strategy.getCampaignType();
            if (campaignType == 2) { // 提升应用安装
                //应用ID
                if (!Check.isNull(appId)) {
                    unitParams.put("app_id", appId);
                }
                // 直达链接
                if (!Check.isNull(strategy.getSchemaUri())) {
                    unitParams.put("schema_uri", strategy.getSchemaUri());
                }
                // 优先从系统应用商店下载
                if (null != strategy.getUseAppMarket()) {
                    unitParams.put("use_app_market", strategy.getUseAppMarket());
                }
                if (null != strategy.getAppStore() && !"".equals(strategy.getAppStore())) {
                    unitParams.put("app_store", JSON.parseArray(strategy.getAppStore()));
                }
            } else if (campaignType == 3) { //  获取电商下单
                //url类型
                if (!Check.isNull(strategy.getUrlType())) {
                    unitParams.put("url_type", strategy.getUrlType());
                }
                if (!Check.isNull(strategy.getUrl())) {
                    unitParams.put("url", strategy.getUrl());
                }
            } else if (campaignType == 5) { //收集销售线索
                //url类型
                if (!Check.isNull(strategy.getWebUriType())) {
                    unitParams.put("web_uri_type", strategy.getWebUriType());
                }
                //url
                if (!Check.isNull(strategy.getUrl())) {
                    unitParams.put("url", strategy.getUrl());
                }
            } else if (campaignType == 7) { //  提高应用活跃
                //  appId
                if (!Check.isNull(appId)) {
                    unitParams.put("app_id", appId);
                }

                //  url
                if (!Check.isNull(strategy.getUrl())) {
                    unitParams.put("url", strategy.getUrl());
                }
                //调起链接
                if (!Check.isNull(strategy.getSchemaUri())) {
                    unitParams.put("schema_uri", strategy.getSchemaUri());
                }
            }
            //投放开始时间
            if (!Check.isNull(strategy.getBeginTime())) {
                unitParams.put("begin_time", strategy.getBeginTime());
            } else {
                unitParams.put("begin_time", DateUtils.formatDate());
            }
            //投放结束时间
            if (!Check.isNull(strategy.getEndTime())) {
                unitParams.put("end_time", strategy.getEndTime());
            }
            //投放时间段
            if (!Check.isNull(strategy.getScheduleTime())) {
                unitParams.put("schedule_time", strategy.getScheduleTime());
            }
            //转化id
            if (!Check.isNull(strategy.getConvertId())) {
                unitParams.put("convert_id", strategy.getConvertId());
            }
            //创意展现方式
            if (!Check.isNull(strategy.getShowMode())) {
                unitParams.put("show_mode", strategy.getShowMode());
            }
            //投放方式
            if (!Check.isNull(strategy.getSpeed())) {
                unitParams.put("speed", strategy.getSpeed());
            }

            if (unitType == 7) {
                //是否开启智能抽帧
                if (!Check.isNull(strategy.getSmartCover())) {
                    unitParams.put("smart_cover", strategy.getSmartCover());
                }
                //程序化创意2.0素材挖掘
                if (!Check.isNull(strategy.getAssetMining())) {
                    if (strategy.getAssetMining() == 1) {
                        unitParams.put("asset_mining", true);
                    } else if (strategy.getAssetMining() == 0) {
                        unitParams.put("asset_mining", false);
                    }
                }
            }
            if (!Check.isNull(strategy.getTemplateIdArray())) {
                //获取项目定向模板数据
                List<String> templateIds = JSONObject.parseObject(strategy.getTemplateIdArray(), List.class);
                List<KuaishouDirectionalPackage> targets = directionalPackageService.getProjectTargetByIds(templateIds);
                if (Check.isNull(targets)) {
                    unitParams.put("errorMsg", "获取项目定向模板失败");
                    insertAccountOperationRecord(strategy, "获取项目定向模板失败", operationType, 0);
                    return unitParams;
                }
                if (!Check.isNull(videoItem)) {
                    targets = checkTemplateIds(targets, videoItem);
                    if (Check.isNull(targets)) {
                        unitParams.put("errorMsg", "未匹配到符合素材的定向");
                        insertAccountOperationRecord(strategy, "未匹配到符合素材的定向", operationType, 0);
                        return unitParams;
                    }
                }
                List<Long> tempIds = new ArrayList<>();
                for (KuaishouDirectionalPackage target : targets) {
                    Long temId = directionalPackageService.selectTemplateId(target.getId(), token.getAccountId());
                    if (!Check.isNull(temId)) {
                        tempIds.add(temId);
                    }
                }
                if (Check.isNull(tempIds)) {
                    unitParams.put("errorMsg", "定向包管理中，该账户未在项目定向模板下进行推送创建");
                    insertAccountOperationRecord(strategy, "定向包管理中，该账户未在项目定向模板下进行推送创建", operationType, 0);
                    return unitParams;
                }

                Long temId = tempIds.get(getrandom(0, tempIds.size() - 1));
                if (!Check.isNull(temId)) {
                    if (sceneId != 5) {
                        unitParams.put("template_id", temId); //定向模板id
                    } else { // 联盟广告位 需要根据模板id 获取定向数据
                        JSONObject unionJson = groupTemplateService.getUnionJson(temId);
                        Integer code = unionJson.getInteger("code");
                        if (code == 0) {
                            JSONObject target = unionJson.getJSONObject("target");
                            unitParams.put("target", target);
                        } else {
                            unitParams.put("errorMsg", "组创建异常=》accountId(" + strategy.getAccountId() + ")联盟广告位定向模板错误");
                            insertAccountOperationRecord(strategy, "联盟广告位定向模板错误", operationType, 0);
                            return unitParams;
                        }
                    }
                }
            } else {
                unitParams.put("errorMsg", "策略未选择定向");
                insertAccountOperationRecord(strategy, "策略未选择定向", operationType, 0);
                return unitParams;
            }
        } catch (Exception e) {
            log.error("整理广告组数据异常", e);
            unitParams.put("errorMsg", "整理广告组数据异常");
        }
        return unitParams;
    }

    /**
     * 筛选符合条件的定向集合
     */
    private List<KuaishouDirectionalPackage> checkTemplateIds(List<KuaishouDirectionalPackage> targets, KuaiShouVideoGet videoItem) {
        try {
            List<KuaishouDirectionalPackage> okTargets = new ArrayList<>();
            QueryWrapper<KuaishouVideoDirectionalPackage> queryWrapper = new QueryWrapper();
            queryWrapper.eq("video_get_id", videoItem.getId());
            queryWrapper.last("limit 1");
            KuaishouVideoDirectionalPackage dir = packageMapper.selectOne(queryWrapper);
            if (Check.isNull(dir)) {
                //素材定向为空，随机获取定向
                return targets;
            } else {
                for (KuaishouDirectionalPackage target : targets) {
                    if (!checkList(dir.getRegion(), target.getRegion())) {
                        continue;
                    }
                    if (!checkList(dir.getDistrictIds(), target.getDistrictIds())) {
                        continue;
                    }
                    if (!Check.isNull(dir.getUserType()) && dir.getUserType() != 2) {
                        if (!dir.getUserType().equals(target.getUserType())) {
                            continue;
                        }
                    }
                    if (!checkList(dir.getAgesRange(), target.getAgesRange())) {
                        continue;
                    }
                    if (!Check.isNull(dir.getMax()) && !Check.isNull(dir.getMin())) {
                        if (Check.isNull(target.getMax()) || Check.isNull(target.getMin())) {
                            continue;
                        }
                        if (dir.getMax() < target.getMin() || dir.getMax() < target.getMin()) {
                            continue;
                        }
                    }
                    if (!Check.isNull(dir.getGender()) && dir.getGender() != 0) {
                        if (!dir.getGender().equals(target.getGender())) {
                            continue;
                        }
                    }
                    if (!Check.isNull(dir.getPlatformOs()) && dir.getPlatformOs() != 0) {
                        if (!dir.getPlatformOs().equals(target.getPlatformOs())) {
                            continue;
                        }
                    }
                    if (!Check.isNull(dir.getAndroidOsv()) && dir.getAndroidOsv() != 3) {
                        if (!dir.getAndroidOsv().equals(target.getAndroidOsv())) {
                            continue;
                        }
                    }
                    if (!Check.isNull(dir.getIosOsv()) && dir.getIosOsv() != 6) {
                        if (!dir.getIosOsv().equals(target.getIosOsv())) {
                            continue;
                        }
                    }
                    if (!Check.isNull(dir.getNetwork()) && dir.getNetwork() != 0) {
                        if (!dir.getNetwork().equals(target.getNetwork())) {
                            continue;
                        }
                    }
                    if (!Check.isNull(dir.getFilterConvertedLevel()) && dir.getFilterConvertedLevel() != 0) {
                        if (!dir.getFilterConvertedLevel().equals(target.getFilterConvertedLevel())) {
                            continue;
                        }
                    }
                    if (!Check.isNull(dir.getBusinessInterestType()) && dir.getBusinessInterestType() != 0) {
                        if (!dir.getBusinessInterestType().equals(target.getBusinessInterestType())) {
                            continue;
                        }
                    }
                    if (!checkList(dir.getDeviceBrand(), target.getDeviceBrand())) {
                        continue;
                    }
                    if (!checkList(dir.getDevicePrice(), target.getDevicePrice())) {
                        continue;
                    }
                    if (!checkList(dir.getBusinessInterest(), target.getBusinessInterest())) {
                        continue;
                    }
                    if (!checkList(dir.getFansStar(), target.getFansStar())) {
                        continue;
                    }
                    if (!checkList(dir.getInterestVideo(), target.getInterestVideo())) {
                        continue;
                    }
                    if (!checkList(dir.getAppInterest(), target.getAppInterest())) {
                        continue;
                    }
                    if (!checkList(dir.getAppIds(), target.getAppIds())) {
                        continue;
                    }
                    if (!Check.isNull(dir.getIsOpen()) && dir.getIsOpen() != 0) {
                        if (!dir.getIsOpen().equals(target.getIsOpen())) {
                            continue;
                        }
                    }
                    if (!Check.isNull(dir.getNoAgeBreak()) && dir.getNoAgeBreak() != 0) {
                        if (!dir.getNoAgeBreak().equals(target.getNoAgeBreak())) {
                            continue;
                        }
                    }
                    if (!Check.isNull(dir.getNoGenderBreak()) && dir.getNoGenderBreak() != 0) {
                        if (!dir.getNoGenderBreak().equals(target.getNoGenderBreak())) {
                            continue;
                        }
                    }
                    if (!Check.isNull(dir.getNoAreaBreak()) && dir.getNoAreaBreak() != 0) {
                        if (!dir.getNoAreaBreak().equals(target.getNoAreaBreak())) {
                            continue;
                        }
                    }
                    if (!checkList(dir.getKeyword(), target.getKeyword())) {
                        continue;
                    }
                    if (!checkList(dir.getLabel(), target.getLabel())) {
                        continue;
                    }
                    if (!checkList(dir.getInterestLabel(), target.getInterestLabel())) {
                        continue;
                    }
                    if (!checkList(dir.getSceneType(), target.getSceneType())) {
                        continue;
                    }
                    if (!Check.isNull(dir.getTimeType()) && dir.getTimeType() != -1) {
                        if (!dir.getTimeType().equals(target.getTimeType())) {
                            continue;
                        }
                    }
                    if (!Check.isNull(dir.getStrengthType()) && dir.getStrengthType() != 0) {
                        if (!dir.getStrengthType().equals(target.getStrengthType())) {
                            continue;
                        }
                    }
                    okTargets.add(target);
                }
            }
            return okTargets;
        } catch (Exception e) {
            log.error("筛选素材定向异常", e);
        }
        return null;
    }

    private boolean checkList(String videoTarget, String target) {
        if (Check.isNull(videoTarget)) {
            //素材是不限，直接返回true。
            return true;
        }
        List videoList = JSONObject.parseObject(videoTarget, List.class);
        if (Check.isNull(videoList)) {
            //素材是不限，直接返回true。
            return true;
        }
        if (Check.isNull(target)) {
            //计划定向是不限，素材非不限，直接返回false。
            return false;
        }
        List list = JSONObject.parseObject(target, List.class);
        if (Check.isNull(list)) {
            //计划定向是不限，素材非不限，直接返回false。
            return false;
        }
        for (Object o : list) {
            if (!videoList.contains(o)) {
                return false;
            }
        }
        return true;
    }

    public static int getrandom(int start, int end) {
        int num = (int) (Math.random() * (end - start + 1) + start);
        return num;
    }

    public static String getActionBar(String actionBarText) {
        if (Check.isNull(actionBarText)) {
            return null;
        }
        String[] split = actionBarText.split(",");
        int i = getrandom(0, split.length - 1);
        return split[i];
    }

    public static String getDescription(String description) {
        if (Check.isNull(description)) {
            return null;
        }
        JSONArray descArr = JSONArray.parseArray(description);
        int i = getrandom(0, descArr.size() - 1);
        return descArr.getString(i);
    }

    private Long getBidByString(String cpaBid) {
        if (Check.isNull(cpaBid)) {
            return null;
        }
        String bidString = null;
        if (cpaBid.contains("/")) { // 阶梯出价
            String[] split = cpaBid.split("/");
            int random = new Random().nextInt(split.length);
            bidString = split[random];

        } else if (cpaBid.contains("-")) { // 随机出价
            String[] split = cpaBid.split("-");
            Double min = Double.valueOf(split[0]) / 1000;
            Double max = Double.valueOf(split[1]) / 1000;
            Double randomNumber = new BigDecimal(min + Math.random() * (max - min)).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
            bidString = String.valueOf(new Double(randomNumber * 1000).longValue());

        } else {
            bidString = cpaBid;
        }

        return Long.valueOf(bidString);
    }

    private void createCreativeByImage(List<MaterialCutFrame> cutFrameList, CtopOauthToken token, JSONObject creativeParams,
                                       Long campaignId, Long unitId, KuaiShouVideoGet videoItem,
                                       int imageNumber, KuaishouProjectStrategy strategy, String uuid, String appVersion) {
        if ((null != cutFrameList && !cutFrameList.isEmpty())) {
            for (int i = 0; i < cutFrameList.size(); i++) {
                creativeParams.put("action_bar_text", getActionBar(strategy.getActionBarText()));
                creativeParams.put("description", getDescription(strategy.getDescription()));
                String imageCode = cutFrameList.get(i).getSignature();
                String imageUrl = cutFrameList.get(i).getUrl();
                String imageToken = getImageToken(imageUrl, imageCode, token.getAccountId(), token.getAccessToken());
                creativeParams.put("image_token", imageToken);
                createCreative(token, creativeParams, campaignId, unitId, i + 1, videoItem, strategy, uuid, appVersion);
                imageNumber--;
                if (imageNumber <= 0) {
                    break;
                }
            }
        }
    }

    private String getImageToken(String imageUrl, String imageCode, Long accountId, String token) {
        // 根据imageUrl 和 imageCode，获取 imageToken （创建创意用）
        KuaiShouImageGet imageGet = imageGetService.getOneByParams(null, imageCode);
        if ((null == imageGet) || ("".equals(imageGet.getImageToken()))) {
            return materialUploadService.kuauiShouImageUpload(imageUrl, imageCode, accountId, token);
        }
        return imageGet.getImageToken();
    }

    private JSONObject creativeParams(CtopOauthToken token, Long unitId, KuaiShouVideoGet videoItem, KuaishouProjectStrategy strategy) {
        JSONObject creativeParams = new JSONObject();
        creativeParams.put("advertiser_id", token.getAccountId());
        creativeParams.put("unit_id", unitId);
        creativeParams.put("photo_id", videoItem.getPhotoId());
        creativeParams.put("creative_material_type", videoItem.getMaterialType());
        // 封面广告语标题
        if (!Check.isNull(strategy.getStickerTitle())) {
            creativeParams.put("sticker_title", strategy.getStickerTitle());
        }
        // 贴纸样式类型
        if (!Check.isNull(strategy.getOverlayType())) {
            creativeParams.put("overlay_type", strategy.getOverlayType());
        }
        // 广告标签
        if (!Check.isNull(strategy.getExposeTag())) {
            creativeParams.put("expose_tag", strategy.getExposeTag());
        }
        // 广告标签2期
        if (Check.isNull(strategy.getNewExposeTag())) {
            creativeParams.put("new_expose_tag", JSON.parseArray(strategy.getNewExposeTag()));
        }
        // 安卓下载中间页ID
        if (Check.isNull(strategy.getSiteId())) {
            creativeParams.put("site_id", strategy.getSiteId());
        }
        if (null != strategy.getClickTrackUrl() && !"".equals(strategy.getClickTrackUrl())) {
            creativeParams.put("click_track_url", strategy.getClickTrackUrl());
        }
        if (null != strategy.getImpressionUrl() && !"".equals(strategy.getImpressionUrl())) {
            creativeParams.put("impression_url", strategy.getImpressionUrl());
        }
        // 第三方有效播放监测链接
        if (!Check.isNull(strategy.getAdPhotoPlayedT3sUrl())) {
            creativeParams.put("ad_photo_played_t3s_url", strategy.getAdPhotoPlayedT3sUrl());
        }
        if (null != strategy.getActionbarClickUrl() && !"".equals(strategy.getActionbarClickUrl())) {
            creativeParams.put("actionbar_click_url", strategy.getActionbarClickUrl());
        }
        if (null != strategy.getCreativeCategory()) {
            creativeParams.put("creative_category", strategy.getCreativeCategory());
        }
        if (null != strategy.getCreativeTag() && !"".equals(strategy.getCreativeTag())) {
            creativeParams.put("creative_tag", JSON.parseArray(strategy.getCreativeTag()));
        }
        return creativeParams;
    }


    private void createCreative(CtopOauthToken token, JSONObject creativeParams, Long campaignId, Long unitId,
                                int creativeCnt, KuaiShouVideoGet videoGet, KuaishouProjectStrategy strategy, String uuid, String appVersion) {
        String creativeName = null;
        if (!Check.isNull(appVersion)) {
            creativeName = appVersion + "_" + creativeCnt;
        } else {
            creativeName = "自定义创意_" + creativeCnt;
        }
        creativeParams.put("creative_name", creativeName);
        Map<String, Object> creativeCreateResult = kuaishouInterfaceService.creativeCreate(token.getAccessToken(), token.getAccountId(), creativeParams, 1);
        Integer creativeCode = (Integer) creativeCreateResult.get("code");
        String creativeMessage = (String) creativeCreateResult.get("message");

        if (creativeCode == -1 && "/rest/openapi/v2/creative/create调用已超日限，次日可恢复调用".equals(creativeMessage)) {
            updateService.updateUnitStatus(token.getAccessToken(), token.getAccountId(), unitId, 3, "e9ca23d68d884d4ebb19d07889727dae");
        } else if (creativeCode == -1 && creativeMessage.contains("超过可关联的有效创意的上限")) {
            updateService.updateUnitStatus(token.getAccessToken(), token.getAccountId(), unitId, 3, "e9ca23d68d884d4ebb19d07889727dae");
        } else if (creativeCode == -1 && creativeMessage.contains("视频不存在")) {
            updateService.updateUnitStatus(token.getAccessToken(), token.getAccountId(), unitId, 3, "e9ca23d68d884d4ebb19d07889727dae");
        }

        AiKuaishouCreativeLevelOperationRecord record = new AiKuaishouCreativeLevelOperationRecord();
        BeanUtils.copyProperties(strategy, record);
        record.setCreativeName(creativeName);
        record.setStatus(creativeCode);
        record.setDescription(creativeParams.getString("description"));
        record.setPhotoId(creativeParams.getString("photo_id"));
        record.setMessage(creativeMessage);
        record.setUnitId(unitId);
        record.setAiStrategyUuid(uuid);
        record.setCreateTime(new Date());
        record.setCreateType(2);//项目自动投放
        if (creativeCode != 0) {
            creativeLevelOperationRecordService.saveOrUpdate(record);
            log.info("创意创建失败=>message:{}", creativeMessage);
            return;
        }
        Long creativeId = (Long) creativeCreateResult.get("creativeId");
        record.setCreativeId(creativeId);
        creativeLevelOperationRecordService.saveOrUpdate(record);
    }

    /**
     * @param wildcard 计划名称/组名称
     * @param strategy 账户id
     * @return 通配符命名规则
     * 日期、渠道号、横竖版（视频素材的横版竖版）、时分、广告位置、素材名称、应用包名、创意制作方式（自定义、程序化）
     */
    private String getName(String wildcard, KuaishouProjectStrategy strategy, Integer createType, String materialName, String type, Long campaignId, Long appId, Integer materialType) {
        if (wildcard.contains("{{应用名称}}") || wildcard.contains("{{应用标记}}") || wildcard.contains("{{应用包名}}")) {
            KuaiShouAppList getAppInfo = appListService.getAppInfo(strategy.getAccountId(), appId);
            if (!Check.isNull(getAppInfo)) {
                wildcard = wildcard.replace("{{应用名称}}", getAppInfo.getAppName());
                wildcard = wildcard.replace("{{应用标记}}", getAppInfo.getAppVersion());
                wildcard = wildcard.replace("{{应用包名}}", getAppInfo.getPackageName());
            } else {
                wildcard = wildcard.replace("{{应用名称}}", "");
                wildcard = wildcard.replace("{{应用标记}}", "");
                wildcard = wildcard.replace("{{应用包名}}", "");
            }
        }
        if (wildcard.contains("{{横竖版}}")) {
            if (!Check.isNull(materialType)) {
                if (materialType == 1) {
                    wildcard = wildcard.replace("{{横竖版}}", "竖版视频");
                } else if (materialType == 2) {
                    wildcard = wildcard.replace("{{横竖版}}", "横版视频");
                } else {
                    wildcard = wildcard.replace("{{横竖版}}", "");
                }
            } else {
                wildcard = wildcard.replace("{{横竖版}}", "");
            }
        }
        if (wildcard.contains("{{创意制作方式}}")) {
            if (strategy.getUnitType() == 4) {
                wildcard = wildcard.replace("{{创意制作方式}}", "自定义");
            } else if (strategy.getUnitType() == 7) {
                wildcard = wildcard.replace("{{创意制作方式}}", "程序化");
            }
        }
        if (wildcard.contains("{{广告位置}}")) {
            String adsence = getAdSenceByParams(strategy.getSceneId());
            wildcard = wildcard.replace("{{广告位置}}", adsence);
        }

        if (wildcard.contains("{{素材名称}}")) {
            if (Check.isNull(materialName)) {
                wildcard = wildcard.replace("{{素材名称}}", "");
            } else {
                wildcard = wildcard.replace("{{素材名称}}", materialName);
            }
        }
        if (wildcard.contains("{{渠道号}}")) {
            KuaiShouAppMultipleBids multipleBids = kuaiShouAppMultipleBidsService.getInfoByAccountAndAppId(strategy.getAccountId(), appId);
            if (!Check.isNull(multipleBids)) {
                wildcard = wildcard.replace("{{渠道号}}", multipleBids.getChannelCode());
            } else {
                wildcard = wildcard.replace("{{渠道号}}", "");
            }
        }
        if (!wildcard.contains("{{自定义}}")) {
            wildcard = wildcard + "{{自定义}}";
        }
        Date date = new Date();
        String nowDate = DateUtils.formatDate(date, "yy-MMdd");
        if ("plan".equals(type)) {
            if (wildcard.contains("{{日期}}")) {
                wildcard = wildcard.replace("{{日期}}", nowDate);
            } else {
                wildcard = wildcard + "-" + nowDate;
            }
        } else if ("unit".equals(type)) {
            wildcard = wildcard.replace("{{日期}}", nowDate);
        }
        String HOUR = DateUtils.formatDate(date, DateUtils.TIME_FORMAT);
        if (wildcard.contains("{{时分}}")) {
            wildcard = wildcard.replace("{{时分}}", HOUR);
        } else {
            wildcard = wildcard.concat(HOUR.substring(0, 4));
        }
        String targetName = KuaishouProjectCreativeMatTypeEnum.getNameByType(strategy.getUnitType().toString() + createType.toString());
        wildcard = wildcard.replace("{{自定义}}", targetName);
        if (!Check.isNull(campaignId)) {
            Integer count = null;
            if (null != strategy.getSingleAppid() && strategy.getSingleAppid() == 2) {
                String redisKey = strategy.getAccountId() + "_" + campaignId;
                Object redisValue = redisUtil.get(redisKey);
                if (Check.isNull(redisValue)) {
                    count = 1;
                    redisUtil.set(redisKey, count);
                } else {
                    count = (Integer) redisValue + 1;
                    redisUtil.set(redisKey, count);
                }
            } else {
                String redisKey = strategy.getAccountId() + "_" + campaignId + nowDate;
                Object redisValue = redisUtil.get(redisKey);
                if (Check.isNull(redisValue)) {
                    count = 1;
                    redisUtil.set(redisKey, count, 100000L);
                } else {
                    count = (Integer) redisValue + 1;
                    redisUtil.set(redisKey, count, 100000L);

                }
            }
            wildcard = wildcard + "-" + count;
        }
        wildcard = wildcard.replace("--", "-");
        wildcard = wildcard.replace("--", "-");
        if (wildcard.startsWith("-")) {
            wildcard = wildcard.substring(1, wildcard.length());
        }
        if (wildcard.endsWith("-")) {
            wildcard = wildcard.substring(0, wildcard.length() - 1);
        }
        return wildcard;
    }

    private String getAdSenceByParams(String sceneIdString) {
        String adsence = "";
        if (null == sceneIdString || "".equals(sceneIdString)) {
            return adsence;
        }
        JSONArray sceneIdArray = JSON.parseArray(sceneIdString);
        if (null == sceneIdArray || sceneIdArray.isEmpty()) {
            return adsence;
        }
        for (int i = 0; i < sceneIdArray.size(); i++) {
            adsence += KuaishouCreativeAdsenceTypeEnum.getNameByType(sceneIdArray.getInteger(i)) + ",";
        }
        return adsence.substring(0, adsence.length() - 1);
    }


    @Override
    public Boolean getUnitOverrun(String keyx) {
        String nowDate = DateUtils.getNowDate("yyyy-MM-dd");
        String key = keyx + "_" + nowDate + "unit_create_overrun";
        Object redisObj = redisUtil.get(key);
        if (Check.isNull(redisObj)) {
            return false;
        }
        Integer value = (Integer) redisObj;
        if (value == 1) {
            return true;
        } else {
            return false;
        }

    }


    /**
     * 记录账户维度操作数据
     *
     * @param strategy 策略
     * @param msg      说明
     * @param errType  异常类型 1 检查错误，2创建时错误
     * @param status   状态 0失败，1成功
     * @throws
     */
    private void insertAccountOperationRecord(KuaishouProjectStrategy strategy, String msg, Integer errType, Integer status) {
        String statDate = DateUtils.formatDate(new Date());
        QueryWrapper<AiKuaishouAccountLevelOperationRecord> wrapper = new QueryWrapper<>();
        wrapper.eq("account_id", strategy.getAccountId());
        wrapper.eq("stat_date", statDate);
        wrapper.last("limit 1");
        AiKuaishouAccountLevelOperationRecord accountOperationRecord = kuaishouAccountLevelOperationRecordService.getOne(wrapper);
        if (Check.isNull(accountOperationRecord)) {
            accountOperationRecord = new AiKuaishouAccountLevelOperationRecord();
            accountOperationRecord.setMessage(msg);
            accountOperationRecord.setProjectId(strategy.getProjectId());
            accountOperationRecord.setAccountId(strategy.getAccountId());
            accountOperationRecord.setErrType(errType);
            accountOperationRecord.setCreateTime(new Date());
            accountOperationRecord.setAiStrategyUuid(strategy.getStrategyUuid());
            accountOperationRecord.setStatDate(statDate);
            accountOperationRecord.setStatus(status);
            kuaishouAccountLevelOperationRecordService.saveOrUpdate(accountOperationRecord);
        } else {
            if (status == 1 && !accountOperationRecord.getAiStrategyUuid().equals(strategy.getStrategyUuid())) {
                accountOperationRecord.setStatus(status);
                accountOperationRecord.setMessage(msg);
                kuaishouAccountLevelOperationRecordService.saveOrUpdate(accountOperationRecord);
            }
            if (status == 0) {
                accountOperationRecord.setAiStrategyUuid(strategy.getStrategyUuid());
                accountOperationRecord.setStatus(status);
                accountOperationRecord.setMessage(msg);
                kuaishouAccountLevelOperationRecordService.saveOrUpdate(accountOperationRecord);
            }
        }
    }

}
