package com.zanxiang.game.module.manage.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zanxiang.game.module.manage.enums.CpSendRoleResultEnum;
import com.zanxiang.game.module.manage.pojo.dto.CpSendMsgResultDTO;
import com.zanxiang.game.module.manage.service.ICpSendMsgLogService;
import com.zanxiang.game.module.manage.service.ICpSendMsgResultService;
import com.zanxiang.game.module.manage.service.IGameSupperService;
import com.zanxiang.game.module.manage.service.IGameUserRoleService;
import com.zanxiang.game.module.manage.utils.SignUtil;
import com.zanxiang.game.module.mybatis.entity.CpSendMsgLog;
import com.zanxiang.game.module.mybatis.entity.CpSendMsgResult;
import com.zanxiang.game.module.mybatis.entity.GameSupper;
import com.zanxiang.game.module.mybatis.entity.GameUserRole;
import com.zanxiang.game.module.mybatis.mapper.CpSendMsgLogMapper;
import com.zanxiang.module.util.JsonUtil;
import com.zanxiang.module.util.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author : lingfeng
 * @time : 2024-03-14
 * @description : CP消息发送记录
 */
@Slf4j
@Service
public class CpSendMsgLogServiceImpl extends ServiceImpl<CpSendMsgLogMapper, CpSendMsgLog> implements ICpSendMsgLogService {

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IGameSupperService gameSupperService;

    @Autowired
    private IGameUserRoleService gameUserRoleService;

    @Autowired
    private ICpSendMsgResultService cpSendMsgResultService;

    @Override
    public void reCpSendMsg(String text, CpSendMsgLog cpSendMsgLog, List<CpSendMsgResult> sendResultList) {
        //查询超父游戏信息
        GameSupper gameSupper = gameSupperService.getGameSupperByGameId(cpSendMsgLog.getGameId());
        if (gameSupper == null || Strings.isBlank(gameSupper.getCpSendMsgUrl()) || Strings.isBlank(gameSupper.getCpSendMsgKey())) {
            log.error("CP发送消息补发, 超父游戏信息不全! cpSendMsgLog : {}, resultList : {}",
                    JsonUtil.toString(cpSendMsgLog), JsonUtil.toString(sendResultList));
            return;
        }
        //角色信息按区服分组
        Map<String, List<CpSendMsgResult>> resultMap = sendResultList.stream()
                .collect(Collectors.groupingBy(CpSendMsgResult::getServerId));
        resultMap.forEach((serverId, cpSendMsgResultList) -> {
            List<String> serverRoleIdList = cpSendMsgResultList.stream().map(CpSendMsgResult::getRoleId).collect(Collectors.toList());
            try {
                CpSendMsgResultDTO result = this.cpSendMsgApi(gameSupper, cpSendMsgLog.getMsgId(), serverId, text, serverRoleIdList);
                this.reResultHandle(cpSendMsgLog, result, cpSendMsgResultList);
            } catch (Exception e) {
                log.error("CP消息发送API调用异常, cpSendMsgLog : {}, sendMsgResultList : {}, e : {}",
                        JsonUtil.toString(cpSendMsgLog), JsonUtil.toString(sendResultList), e.getMessage(), e);
            }
        });
    }

    private void reResultHandle(CpSendMsgLog cpSendMsgLog, CpSendMsgResultDTO result, List<CpSendMsgResult> sendMsgResultList) {
        //循环处理结果
        sendMsgResultList.forEach(sendMsgResult -> {
            //状态判断
            CpSendRoleResultEnum resultEnum = result.getFailList().contains(sendMsgResult.getRoleId()) ?
                    CpSendRoleResultEnum.CP_SEND_ROLE_RESULT_FAIL : CpSendRoleResultEnum.CP_SEND_ROLE_RESULT_SUCCESS;
            sendMsgResult.setSendStatus(resultEnum.getValue());
            sendMsgResult.setUpdateTime(LocalDateTime.now());
        });
        //在同一个事物中进行表更新
        transactionTemplate.execute(status -> {
            cpSendMsgResultService.updateBatchById(sendMsgResultList);
            super.update(new LambdaUpdateWrapper<CpSendMsgLog>()
                    .setSql("success_count=success_count+" + result.getSucessCount())
                    .setSql("fail_count=fail_count-" + result.getSucessCount())
                    .eq(CpSendMsgLog::getMsgId, cpSendMsgLog.getMsgId())
            );
            return Boolean.TRUE;
        });
    }

    @Override
    public void cpSendMsg(Long taskId, Long gameId, String text, List<String> roleIdList) {
        //查询角色区服信息
        List<GameUserRole> gameUserRoleList = gameUserRoleService.list(new LambdaQueryWrapper<GameUserRole>()
                .select(GameUserRole::getGameId, GameUserRole::getServerId, GameUserRole::getRoleId)
                .eq(GameUserRole::getGameId, gameId)
                .in(GameUserRole::getRoleId, roleIdList));
        String msgId = UUID.randomUUID().toString().replace("-", "");
        //保存发送记录
        CpSendMsgLog cpSendMsgLog = this.transform(taskId, gameId, msgId, gameUserRoleList.size());
        super.save(cpSendMsgLog);
        if (CollectionUtils.isEmpty(gameUserRoleList)) {
            log.error("CP发送消息参数错误, 角色列表信息不存在! taskId : {}, gameId : {}, roleIdList : {}",
                    taskId, gameId, JsonUtil.toString(roleIdList));
            return;
        }
        //查询超父游戏信息
        GameSupper gameSupper = gameSupperService.getGameSupperByGameId(gameId);
        if (gameSupper == null || Strings.isBlank(gameSupper.getCpSendMsgUrl()) || Strings.isBlank(gameSupper.getCpSendMsgKey())) {
            log.error("CP发送消息参数错误, 超父游戏信息不全! taskId : {}, gameId : {}, roleIdList : {}, gameSupper : {}",
                    taskId, gameId, JsonUtil.toString(roleIdList), JsonUtil.toString(gameSupper));
            return;
        }
        //角色信息按区服分组
        Map<String, List<GameUserRole>> serverIdRoleMap = gameUserRoleList.stream()
                .collect(Collectors.groupingBy(GameUserRole::getServerId));
        serverIdRoleMap.forEach((serverId, roleList) -> {
            List<String> serverRoleIdList = roleList.stream().map(GameUserRole::getRoleId).collect(Collectors.toList());
            CpSendMsgResultDTO result = null;
            try {
                result = this.cpSendMsgApi(gameSupper, msgId, serverId, text, serverRoleIdList);
                this.resultHandle(cpSendMsgLog, result, serverId, serverRoleIdList);
            } catch (Exception e) {
                log.error("CP消息发送API调用异常, serverId : {}, roleList : {}, result : {}, e : {}",
                        serverId, roleList, JsonUtil.toString(result), e.getMessage(), e);
            }
        });
    }

    private CpSendMsgLog transform(Long taskId, Long gameId, String msgId, Integer roleCount) {
        return CpSendMsgLog.builder()
                .msgId(msgId)
                .taskId(taskId)
                .gameId(gameId)
                .roleCount(roleCount)
                .successCount(0L)
                .failCount(0L)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();
    }

    private void resultHandle(CpSendMsgLog cpSendMsgLog, CpSendMsgResultDTO result, String serverId, List<String> roleList) {
        //结果列表
        List<CpSendMsgResult> resultList = new ArrayList<>();
        roleList.forEach(roleId -> {
            //状态判断
            CpSendRoleResultEnum resultEnum = result.getFailList().contains(roleId) ?
                    CpSendRoleResultEnum.CP_SEND_ROLE_RESULT_FAIL : CpSendRoleResultEnum.CP_SEND_ROLE_RESULT_SUCCESS;
            resultList.add(this.transform(cpSendMsgLog.getTaskId(), cpSendMsgLog.getMsgId(), resultEnum.getValue(),
                    cpSendMsgLog.getGameId(), serverId, roleId));
        });
        //在同一个事物中进行表更新
        transactionTemplate.execute(status -> {
            cpSendMsgResultService.saveBatch(resultList);
            super.update(new LambdaUpdateWrapper<CpSendMsgLog>()
                    .setSql("success_count=success_count+" + result.getSucessCount())
                    .setSql("fail_count=fail_count+" + result.getFailList().size())
                    .eq(CpSendMsgLog::getMsgId, cpSendMsgLog.getMsgId())
            );
            return Boolean.TRUE;
        });
    }

    private CpSendMsgResult transform(Long taskId, String msgId, String sendStatus, Long gameId, String serverId, String roleId) {
        return CpSendMsgResult.builder()
                .taskId(taskId)
                .msgId(msgId)
                .gameId(gameId)
                .serverId(serverId)
                .roleId(roleId)
                .sendStatus(sendStatus)
                .createTime(LocalDateTime.now())
                .build();
    }

    @Override
    public CpSendMsgResultDTO cpSendMsgApi(GameSupper gameSupper, String msgId, String serverId, String text, List<String> roleIdList) {
        long time = System.currentTimeMillis() / 1000;
        Map<String, Object> param = new HashMap<>(8);
        param.put("msgId", msgId);
        param.put("strRan", msgId);
        param.put("time", time);
        param.put("sign", SignUtil.md5("cpServerKey=" + gameSupper.getCpSendMsgKey() + "&msgId=" + msgId + "&strRan=" + msgId + "&time=" + time));
        param.put("pushType", 1);
        param.put("serverid", serverId);
        param.put("roleIds", roleIdList);
        //图片地址弄一张最小的, CP方不会用, 有默认底图
        Map<String, Object> msgContent = new HashMap<>(2);
        msgContent.put("text", text);
        //攻守CP方前端存在BUG, 这个图片地址不会展示, 但是必须给过去, 否则弹窗无法弹出
        if (Objects.equals(gameSupper.getId(), 2L)) {
            msgContent.put("imgs", JsonUtil.toString(Collections.singletonList("https://manage.84game.cn/image/WechatIMG56.jpeg")));
        }
        //增加自定义客服图片和获客链接参数 -梦回CP方已接入
        if (Strings.isNotBlank(gameSupper.getCpSendMsgConfig())) {
            JSONObject msgConfig = JSONObject.parse(gameSupper.getCpSendMsgConfig());
            msgContent.put("qrCode", msgConfig.getString("qrCode"));
            msgContent.put("superLink", msgConfig.getString("superLink"));
        }
        //添加消息参数内容
        param.put("msgContent", msgContent);
        //请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.set(HttpHeaders.ACCEPT_CHARSET, "UTF-8");
        HttpEntity<String> request = new HttpEntity<>(JsonUtil.toString(param), headers);
        String result;
        try {
            result = restTemplate.postForObject(gameSupper.getCpSendMsgUrl(), request, String.class);
            log.error("CP推送消息结果, result : {}", result);
        } catch (Exception e) {
            log.error("CP推送消息异常, e : {}", e.getMessage(), e);
            throw new BaseException("消息发送失败");
        }
        return JsonUtil.toObj(result, CpSendMsgResultDTO.class);
    }
}
