package com.fs.app.facade;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fs.common.utils.RedisUtil;
import com.fs.common.utils.SnowflakeUtil;
import com.fs.newAdv.domain.LandingPageTemplate;
import com.fs.newAdv.domain.Lead;
import com.fs.newAdv.domain.Site;
import com.fs.newAdv.dto.req.QwExternalIdBindTrackReq;
import com.fs.newAdv.dto.req.WeChatLandingIndexReq;
import com.fs.newAdv.dto.req.updateNickNameReq;
import com.fs.newAdv.dto.res.LandingIndexRes;
import com.fs.newAdv.enums.AdvertiserTypeEnum;
import com.fs.newAdv.integration.adapter.IAdvertiserAdapter;
import com.fs.newAdv.integration.factory.AdvertiserHandlerFactory;
import com.fs.newAdv.service.ILandingPageTemplateService;
import com.fs.newAdv.service.ILeadService;
import com.fs.newAdv.service.ISiteService;
import com.fs.qw.domain.QwAssignRule;
import com.fs.qw.domain.QwAssignRuleUser;
import com.fs.qw.domain.QwContactWay;
import com.fs.qw.domain.QwGroupActual;
import com.fs.qw.service.IQwAssignRuleService;
import com.fs.qw.service.IQwAssignRuleUserService;
import com.fs.qw.service.IQwContactWayService;
import com.fs.qw.service.IQwGroupActualService;
import com.fs.qwApi.Result.QwAddContactWayResult;
import com.fs.qwApi.param.QwAddContactWayParam;
import com.fs.qwApi.service.QwApiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

@Service
@Slf4j
public class CallbackProcessingFacadeServiceImpl implements CallbackProcessingFacadeService {
    @Autowired
    private AdvertiserHandlerFactory handlerFactory;
    @Autowired
    private ILeadService leadService;
    @Autowired
    private ISiteService siteService;
    @Autowired
    private IQwAssignRuleUserService assignRuleUserService;
    @Autowired
    private IQwAssignRuleService assignRuleService;
    @Autowired
    private ILandingPageTemplateService landingPageTemplateService;
    @Autowired
    private IQwGroupActualService actualService;
    @Autowired
    private QwApiService qwApiService;
    @Autowired
    private IQwContactWayService contactWayService;

    @Autowired
    private RedisUtil redisUtil;

    private static final String TEMPLATE_DATA = "new-adv:template-data:";

    @Override
    public void saveClickTrace(Long advertiserCode, Map<String, String> allParams) {
        IAdvertiserAdapter advertiserAdapter = handlerFactory.getAdapter(AdvertiserTypeEnum.getByCode(advertiserCode));
        Lead lead = advertiserAdapter.adaptCallbackData(allParams);
        Lead byClickId = leadService.getByClickId(lead.getTraceId());
        if (ObjectUtil.isNotEmpty(byClickId)) {
            log.info("线索已存在:{}", lead.getTraceId());
            return;
        }
        lead.setStatus(0);
        lead.setClickTrigger(1);
        lead.setTraceRawParams(JSONUtil.toJsonStr(allParams));
        lead.setTraceId(SnowflakeUtil.randomUUID());
        boolean saved = leadService.save(lead);
        if (!saved) {
            log.error("线索保存失败:{}", lead);
        }
    }

    private String getTraceIdByAdvertiser(AdvertiserTypeEnum byCode, Map<String, String> allParams) {
        String clickId;
        switch (byCode) {
            case OCEANENGINE:
            case TENCENT:
                clickId = allParams.get("clickid");
                break;
            case OPPO:
                clickId = allParams.get("tid");
                break;
            case BAIDU:
                clickId = allParams.get("bd_vid");
                break;
            case VIVO:
                clickId = allParams.get("requestId");
                break;
            case IQIYI:
                clickId = allParams.get("traceId");
                break;
            default:
                clickId = "ylrz_test";
        }
        if (StrUtil.isEmpty(clickId)) {
            clickId = "ylrz_test" + IdUtil.randomUUID();
        }

        return clickId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LandingIndexRes getLandingIndexBySiteId(String viewUrl, Map<String, String> allParams) {
        // 站点信息
        String paramsSiteId = allParams.get("siteId");
        if (ObjectUtil.isEmpty(paramsSiteId)) {
            log.info("站点id不存在:{}", paramsSiteId);
            return null;
        }
        Long siteId = Long.valueOf(paramsSiteId);
        Site byId = siteService.getById(siteId);
        if (ObjectUtil.isEmpty(byId)) {
            log.info("站点信息不存在:{}", siteId);
            return null;
        }
        // 广告商信息
        Long advertiserId = byId.getAdvertiserId();
        // 访问链路id
        String clickId = getTraceIdByAdvertiser(Objects.requireNonNull(AdvertiserTypeEnum.getByCode(advertiserId)), allParams);
        // 线索信息
        Lead lead = leadService.getByClickId(clickId);
        boolean isNewLead = ObjectUtil.isEmpty(lead);
        if (isNewLead) {
            IAdvertiserAdapter advertiserAdapter = handlerFactory.getAdapter(AdvertiserTypeEnum.getByCode(advertiserId));
            lead = advertiserAdapter.adaptCallbackData(allParams);
            lead.setAdvertiserId(advertiserId);
            lead.setSiteId(siteId);
            lead.setClickId(clickId);
            // 设置站点和落地页的关联
            setSiteByIdeaId(siteId, lead.getIdeaId());
        } else {
            // 检查站点和广告商信息是否异常
            if (!Objects.equals(lead.getSiteId(), siteId)) {
                log.info("落地页站点信息异常:{}---{}", lead.getSiteId(), siteId);
            }
            if (!Objects.equals(lead.getAdvertiserId(), advertiserId)) {
                log.info("落地页广告商信息异常:{}---{}", lead.getAdvertiserId(), advertiserId);
            }
        }
        // 模板缓存
/*        Object ca = redisUtil.get(TEMPLATE_DATA + traceId);
        String templateData;
        if (ca != null) {
            templateData = String.valueOf(ca);
        } else {
            // 查询模板数据
            LandingPageTemplate landingPageTemplate = landingPageTemplateService.getById(byId.getLaunchPageId());
            JSONObject jsonObject = JSONUtil.parseObj(landingPageTemplate.getTemplateData());
            // 替换二维码链接
            updateQrCodeInTemplate(jsonObject, traceId, byId, byTraceId);
            templateData = JSONUtil.toJsonStr(jsonObject);
        }*/

        // 查询模板数据
        LandingPageTemplate landingPageTemplate = landingPageTemplateService.getById(byId.getLaunchPageId());
        JSONObject jsonObject = JSONUtil.parseObj(landingPageTemplate.getTemplateData());
        // 替换二维码链接
        updateQrCodeInTemplate(jsonObject, byId, lead);
        String templateData = JSONUtil.toJsonStr(jsonObject);

        // 保存或更新 线索信息
        LocalDateTime now = LocalDateTime.now();
        lead.setLandingPageRawParams(JSONUtil.toJsonStr(allParams));
        lead.setLandingPageTrigger(1);
        lead.setLandingPageTs(now);
        lead.setUpdateTime(now);
        lead.setViewUrl(viewUrl);
        if (isNewLead) {
            lead.setTraceId(SnowflakeUtil.randomUUID());
            leadService.save(lead);
        } else {
            leadService.updateById(lead);
        }

        // 封装返回结果
        LandingIndexRes res = new LandingIndexRes();
        redisUtil.set(TEMPLATE_DATA + lead.getTraceId(), templateData, 24, TimeUnit.HOURS);
        res.setTemplateData(templateData);
        res.setTraceId(lead.getTraceId());
        return res;
    }

    private void setSiteByIdeaId(Long siteId, String ideaId) {
        siteService.update(new LambdaUpdateWrapper<Site>()
                .eq(Site::getId, siteId)
                .set(Site::getIdeaId, ideaId));
    }

    /**
     * 更新模板中的二维码信息
     */
    private void updateQrCodeInTemplate(JSONObject templateData, Site site, Lead lead) {
        JSONArray configList = templateData.getJSONArray("configList");
        if (configList == null || configList.isEmpty()) {
            return;
        }
        AtomicReference<String> qrCode = new AtomicReference<>("");
        configList.stream()
                .map(config -> (JSONObject) config)
                .map(config -> config.getJSONArray("moduleList"))
                .filter(ObjectUtil::isNotEmpty)
                .flatMap(Collection::stream)
                .map(module -> (JSONObject) module)
                .filter(module -> "h5-qrcode".equals(module.getStr("type")))
                .forEach(module -> {
                    if (StrUtil.isEmpty(qrCode.get())) {
                        qrCode.set(getQrCodeByAllocationRuleId(site.getLaunchType(), site.getAllocationRule(), site.getAllocationRuleId(), lead));
                    }
                    module.set("workUrl", qrCode.get());
                });
    }

    private String getQrCodeByAllocationRuleId(Integer launchType,
                                               Integer allocationRule,
                                               Long allocationRuleId,
                                               Lead byTraceId) {
        log.info("开始获取广告二维码: {} {} {} {}", launchType, allocationRule, allocationRuleId, byTraceId);
        // 二维码
        String qrCode = "";
        if (allocationRule == 1) {
            // 个人分配规则
            QwAssignRule byId1 = assignRuleService.getById(allocationRuleId);
            QwAssignRuleUser qwAssignRuleUser = assignRuleUserService.getUserByAllocationRuleId(allocationRuleId, byId1.getAssignType());
            byTraceId.setQwAssignRuleUserId(qwAssignRuleUser.getId());
            if (byId1.getAssignType().equals(3)) {
                List<String> users = Collections.singletonList(qwAssignRuleUser.getQwUserId());
                QwAddContactWayParam qwAddContactWayParam = new QwAddContactWayParam();
                qwAddContactWayParam.setType(1);
                qwAddContactWayParam.setScene(2);
                qwAddContactWayParam.setUser(users);
                qwAddContactWayParam.setSkip_verify(true);
                QwAddContactWayResult qwAddContactWayResult = qwApiService.addContactWay(qwAddContactWayParam, qwAssignRuleUser.getCorpId());
                qrCode = qwAddContactWayResult.getQr_code();
            }
        } else if (allocationRule == 2) {
            // 活码分配规则
            if (launchType.equals(1)) {
                // 线上规则--群活码
                QwGroupActual qwGroupActual = actualService.getGroupActualByAllocationRuleId(allocationRuleId);
                byTraceId.setQwGroupActualId(qwGroupActual.getId());
                byTraceId.setQwGroupLiveCodeId(qwGroupActual.getLiveCodeId());
                qrCode = qwGroupActual.getGroupUrl();
            } else if (launchType.equals(2)) {
                // 线下规则--个人活码
                QwContactWay qwContactWay = contactWayService.selectQwContactWayById(allocationRuleId);
                byTraceId.setQwContactWayId(qwContactWay.getId());
                qrCode = qwContactWay.getQrCode();
            }
        }
        log.info("落地页广告获取二维码: {}", qrCode);
        return qrCode;
    }

    @Override
    public void gdtGetAuthCode(Integer code, Long state) {
   /*     if (code == null || state == null) {
            return;
        }
        PromotionAccount byId = promotionAccountService.getById(state);
        if (byId == null) {
            return;
        }
        IApiClient apiClient = handlerFactory.getApiClient(AdvertiserTypeEnum.TENCENT);
        if (apiClient instanceof IAccessTokenClient) {
            IAccessTokenClient tokenClient = (IAccessTokenClient) apiClient;
            Map<String, String> accessToken = tokenClient.getAccessToken(code, byId.getAppId(), byId.getAppSecret(), byId.getCallbackUrl());
            byId.setAccessToken(accessToken.get("access_token"));
            byId.setRefreshToken(accessToken.get("refresh_token"));
        }*/
    }

    @Override
    public LandingIndexRes getWxLandingIndexBySiteId(WeChatLandingIndexReq req) {
        // 更新授权页访问信息记录
        leadService.updateAuthIndex(req.getTraceId(), req.getType());
        String templateData = String.valueOf(redisUtil.get(TEMPLATE_DATA + req.getTraceId()));
        LandingIndexRes landingIndexRes = new LandingIndexRes();
        landingIndexRes.setTemplateData(templateData);
        return landingIndexRes;
    }

    @Override
    public void qwExternalIdBindTrack(QwExternalIdBindTrackReq req) {
        // 广告线索处理
        leadService.updateAddMemberLead(req.getQwExternalId(), req.getUnionid());
    }

    @Override
    public void updateNickName(updateNickNameReq req) {
        Lead byTraceId = leadService.getByTraceId(req.getTraceId());
        if (ObjectUtil.isEmpty(byTraceId)) {
            log.error("更新昵称失败，未找到线索:{}", req);
        }
        Lead update = new Lead();
        update.setId(byTraceId.getId());
        update.setWeiChatName(req.getNickName());
        leadService.updateById(update);
    }
}
