package com.fs.ad.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fs.ad.apis.IqiyiApiUtil;
import com.fs.ad.apis.YouKuApiUtils;
import com.fs.ad.domain.*;
import com.fs.ad.enums.AdUploadType;
import com.fs.ad.iqiyi.vo.IyiqiDataVo;
import com.fs.ad.mapper.*;
import com.fs.ad.service.IAdHtmlClickLogService;
import com.fs.ad.yk.vo.DataBackVo;
import com.fs.baidu.api.ConvertData;
import com.fs.baidu.domain.BdAccount;
import com.fs.baidu.mapper.BdAccountMapper;
import com.fs.baidu.param.ConversionType;
import com.fs.baidu.vo.ad.AdBaiduClickCallbackVo;
import com.fs.baidu.vo.ad.AdBaseClickCallbackVo;
import com.fs.baidu.vo.ad.AdIqiyiClickCallbackVo;
import com.fs.baidu.vo.ad.AdYouKuClickCallbackVo;
import com.fs.common.core.redis.RedisCacheT;
import com.fs.common.exception.base.BaseException;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.StringUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 广告点击Service业务层处理
 * 
 * @author fs
 * @date 2025-01-09
 */
@Slf4j
@Service
@AllArgsConstructor
public class AdHtmlClickLogServiceImpl extends ServiceImpl<AdHtmlClickLogMapper, AdHtmlClickLog> implements IAdHtmlClickLogService
{
    private final AdHtmlClickLogMapper adHtmlClickLogMapper;
    private final RedisCacheT<AdHtmlClickLog> redisCache;
    private final RedisCacheT<Integer> redisCacheType;
    private final AdYoukuAccountMapper adYoukuAccountMapper;
    private final BdAccountMapper bdAccountMapper;
    private final AdSiteMapper adSiteMapper;
    private final AdAccountMapper adAccountMapper;
    private final AdUploadLogMapper adUploadLogMapper;

    public static  final String AD_LOG_KEY = "AD:";
    public static  final String AD_TYPE_LOG_KEY = "ADTYPE:";
    public static  final Integer EXPIRATION_TIME = 1;

    /**
     * 查询广告点击
     * 
     * @param id 广告点击主键
     * @return 广告点击
     */
    @Override
    public AdHtmlClickLog selectAdHtmlClickLogById(Long id)
    {
        return adHtmlClickLogMapper.selectAdHtmlClickLogById(id);
    }

    /**
     * 查询广告点击列表
     * 
     * @param adHtmlClickLog 广告点击
     * @return 广告点击
     */
    @Override
    public List<AdHtmlClickLog> selectAdHtmlClickLogList(AdHtmlClickLog adHtmlClickLog)
    {
        return adHtmlClickLogMapper.selectAdHtmlClickLogList(adHtmlClickLog);
    }

    /**
     * 新增广告点击
     * 
     * @param adHtmlClickLog 广告点击
     * @return 结果
     */
    @Override
    public int insertAdHtmlClickLog(AdHtmlClickLog adHtmlClickLog)
    {
        adHtmlClickLog.setCreateTime(DateUtils.getNowDate());
        return adHtmlClickLogMapper.insertAdHtmlClickLog(adHtmlClickLog);
    }

    /**
     * 修改广告点击
     * 
     * @param adHtmlClickLog 广告点击
     * @return 结果
     */
    @Override
    public int updateAdHtmlClickLog(AdHtmlClickLog adHtmlClickLog)
    {
        adHtmlClickLog.setUpdateTime(DateUtils.getNowDate());
        return adHtmlClickLogMapper.updateAdHtmlClickLog(adHtmlClickLog);
    }

    /**
     * 批量删除广告点击
     * 
     * @param ids 需要删除的广告点击主键
     * @return 结果
     */
    @Override
    public int deleteAdHtmlClickLogByIds(Long[] ids)
    {
        return adHtmlClickLogMapper.deleteAdHtmlClickLogByIds(ids);
    }

    /**
     * 删除广告点击信息
     * 
     * @param id 广告点击主键
     * @return 结果
     */
    @Override
    public int deleteAdHtmlClickLogById(Long id)
    {
        return adHtmlClickLogMapper.deleteAdHtmlClickLogById(id);
    }

    @Override
    public void upload(String state, AdUploadType clickType) {
        try {
            Integer type = redisCacheType.getCacheObject(AD_TYPE_LOG_KEY +state);
            if(type == null){
                log.error("未找到对应类型：{}", state);
                return;
            }
            log.info("广告投流上传信息：vid：{}，上传类型：{}", state, clickType);
            String key = genKey(state, type, clickType);
            AdHtmlClickLog one = redisCache.getCacheObject(key);
            log.info("redis-key:{};;;data:{}", key, one);
            if(one == null){
                List<AdHtmlClickLog> list = list(new QueryWrapper<AdHtmlClickLog>().eq("vid", state).eq("type", type));
                if(!list.isEmpty()){
                    one = list.get(0);
                    if(one != null){
                        one.setMysql(true);
                    }
                    log.info("redis空数据库信息：{}", one);
                }
            }
            if(one != null){
                String uploadType = clickType.name();
                Integer i = adUploadLogMapper.selectCount(new QueryWrapper<AdUploadLog>().eq("vid", one.getVid()).like("upload_type", uploadType));
                if(i > 0){
                    log.info("vid：{}， {}已经上传次数{}", one.getVid(), uploadType, i);
                    return;
                }
                switch (type){
                    case 0: // 百度
                        uploadBaiDu(one, clickType);
                    case 1:// 优酷
                        uploadYouKu(one, clickType);
                    case 2:// 爱奇艺
                        uploadIqiyi(one, clickType);
                }
                one.setUploadType(uploadType);
                saveLog(key, one, type);

                AdUploadLog adUploadLog = new AdUploadLog();
                if(one.getSiteId() != null){
                    AdSite adSite = adSiteMapper.selectById(one.getSiteId());
                    adUploadLog.setSiteId(one.getSiteId());
                    adUploadLog.setTemplateId(adSite.getTemplateId());
                    adUploadLog.setDomainId(adSite.getDomainId());
                }
                adUploadLog.setType(one.getType());
                adUploadLog.setAccountId(one.getAccountId());
                adUploadLog.setUrl(one.getUrl());
                adUploadLog.setUploadType(uploadType);
                adUploadLog.setVid(one.getVid());
                adUploadLogMapper.insert(adUploadLog);
            }


        }catch (Throwable e){
            e.printStackTrace();
            log.error("上传信息错误：\r\n错误信息{}\r\n参数{};{}", e.getMessage(), state, clickType);
        }
    }

    private void uploadBaiDu(AdHtmlClickLog one, AdUploadType clickType){
        if(one.getAccountId() == null) return;
        AdAccount accountBase = adAccountMapper.selectById(one.getAccountId());
        BdAccount account = bdAccountMapper.selectById(accountBase.getLinkId());
        ConvertData.sendConvertData(account.getToken(), Collections.singletonList(ConversionType.builder().logidUrl(one.getUrl()).newType(clickType.getBdType()).build()));
    }
    private void uploadYouKu(AdHtmlClickLog one, AdUploadType clickType){
        if(clickType != AdUploadType.ADD_WX || one.getAccountId() == null) return;
        AdAccount accountBase = adAccountMapper.selectById(one.getAccountId());
        AdYoukuAccount account = adYoukuAccountMapper.selectById(accountBase.getLinkId());
        if(account == null){
            log.error("上传优酷未找到账号信息：{}", one.getAccountId());
            return;
        }
        YouKuApiUtils.sendYk(Collections.singletonList(DataBackVo.builder().trackId(one.getVid()).creativeId(one.getAid()).key(account.getAppKey()).token(account.getToken()).build()));
    }
    private void uploadIqiyi(AdHtmlClickLog one, AdUploadType clickType){
        if(clickType != AdUploadType.ADD_WX) return;
        IqiyiApiUtil.dataBack(IyiqiDataVo.builder().impressId(one.getVid()).eventType(one.getClickType()).build());
    }

    @Override
    public void setLogIqiyi(AdIqiyiClickCallbackVo vo) {
        if(StringUtils.isNotEmpty(vo.getNo())){
            int type = 2;
            String clickType = vo.getClickType();
            String key = genKey(vo.getVid(), type, clickType);
            AdHtmlClickLog one = redisCache.getCacheObject(key);
            if(one == null){
                one = getOne(new QueryWrapper<AdHtmlClickLog>().eq("type", type).eq("vid", vo.getVid()).eq("click_type", clickType));
                if(one != null){
                    one.setMysql(true);
                }
            }
            if(one == null) {
                one = new AdHtmlClickLog();
                one.setCreateTime(DateUtils.getNowDate());
            }
            if(vo.getId() != null){
                AdSite adSite = adSiteMapper.selectById(vo.getId());
                one.setAccountId(adSite.getAccountId());
            }
            one.setType(type);
            one.setUrl(vo.getUrl());
            one.setHtmlNo(vo.getNo());
            one.setVid(vo.getVid());
            one.setAccountId(vo.getAccountId());
            one.setClickType(clickType);
            one.setLastTime(LocalDateTime.now().plusDays(1));
            one.setUpdateTime(DateUtils.getNowDate());
            saveLog(key, one, type);
        }else{
            saveLog(vo, e -> {
                e.setPid(vo.getPlanId());
                e.setAid(vo.getCreativeId());
            });
        }
    }

    @Override
    public void setLogBaiDu(AdBaiduClickCallbackVo vo) {
        saveLog(vo, null);
    }

    @Override
    public void setLogYouKu(AdYouKuClickCallbackVo vo) {
        saveLog(vo, e -> {
            e.setAid(vo.getAid());
        });
    }

    @Override
    public void setLogBaiDuApi(AdBaiduClickCallbackVo vo) {
        Integer type = 0;
        AdHtmlClickLog one = getLog(vo.getVid(), type, vo.getClickType());
        one.setAid(vo.getAid());
        one.setPid(vo.getPid());
        one.setUid(vo.getUid());
        one.setUserid(vo.getUserid());
        one.setCombId(vo.getCombId());
        String key = genKey(vo.getVid(), type, vo.getClickType());
        saveLog(key, one, type);
    }

    private <T extends AdBaseClickCallbackVo> void saveLog(T vo, Consumer<AdHtmlClickLog> fun){
        AdSite adSite = adSiteMapper.selectById(vo.getId());
        Integer type = 99;
        if(adSite != null){
            type = adSite.getType();
        }
        String key = genKey(vo.getVid(), type, vo.getClickType());
        AdHtmlClickLog one = getLog(vo.getVid(), type, vo.getClickType());
        if(adSite != null){
            one.setAccountId(adSite.getAccountId());
        }
        one.setType(type);
        one.setSiteId(vo.getId());
        one.setUrl(vo.getUrl());
        one.setVid(vo.getVid());
        one.setClickType(vo.getClickType());
        one.setBackJson(JSON.toJSONString(vo));
        one.setLastTime(LocalDateTime.now().plusDays(1));
        one.setUpdateTime(DateUtils.getNowDate());
        if(fun != null){
            fun.accept(one);
        }
        saveLog(key, one, type);
    }

    private void saveLog(String key, AdHtmlClickLog one, Integer type){
        if(one.isMysql()){
            updateById(one);
        }else{
            redisCache.setCacheObject(key, one, EXPIRATION_TIME, TimeUnit.DAYS);
            redisCacheType.setCacheObject(AD_TYPE_LOG_KEY + one.getVid(), type, EXPIRATION_TIME, TimeUnit.DAYS);
        }
    }


    private AdHtmlClickLog getLog(String vid, Integer type, String clickType){
        String key = genKey(vid, type, clickType);
        AdHtmlClickLog one = redisCache.getCacheObject(key);
        if(one == null){
            one = getOne(new QueryWrapper<AdHtmlClickLog>().eq("type", type).eq("vid", vid).eq("click_type", clickType));
            if(one != null){
                one.setMysql(true);
            }
        }
        if(one == null) {
            one = new AdHtmlClickLog();
            one.setCreateTime(DateUtils.getNowDate());
        }
        return one;
    }

    private String genKey(String vid, Integer type, AdUploadType clickType) {
        if(type == 0){
            return AD_LOG_KEY + vid + ":" + type + ":" + clickType.getBdType();
        }
        if(type == 1){
            return AD_LOG_KEY + vid + ":" + type + ":" + clickType.getYoukuType();
        }
        if(type == 2){
            return AD_LOG_KEY + vid + ":" + type + ":" + clickType.getIqiyiType();
        }
        throw new BaseException("错误类型");
    }

    public static String genKey(String vid, Integer type, String clickType){
        return AD_LOG_KEY + vid + ":" + type + ":" + clickType;
    }
}
