package com.zanxiang.game.back.serve.rpc.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zanxiang.game.back.base.ServerInfo;
import com.zanxiang.game.back.base.pojo.dto.TencentMiniGameOrderBackQueryRpcDTO;
import com.zanxiang.game.back.base.pojo.dto.TencentOrderDTO;
import com.zanxiang.game.back.base.pojo.dto.TencentRoleRegisterRpcDTO;
import com.zanxiang.game.back.base.pojo.dto.TencentUserDTO;
import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
import com.zanxiang.game.back.base.pojo.vo.OrderBackQueryRpcVO;
import com.zanxiang.game.back.base.rpc.ITencentMiniGameBackRpc;
import com.zanxiang.game.back.serve.pojo.entity.*;
import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
import com.zanxiang.game.back.serve.pojo.enums.BackTypeEnum;
import com.zanxiang.game.back.serve.service.*;
import com.zanxiang.module.util.JsonUtil;
import com.zanxiang.module.util.pojo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@DubboService
public class TencentMiniGameBackRpcImpl implements ITencentMiniGameBackRpc {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private IGameBackPolicyService gameBackPolicyService;

    @Autowired
    private IGameTencentMiniGameOrderService gameTencentMiniGameOrderService;

    @Autowired
    private IGameTencentMiniGameUserService gameTencentMiniGameUserService;

    @Autowired
    private IGameTencentMiniGameCallbackService gameTencentMiniGameCallbackService;

    @Autowired
    private IGameTencentMiniGameRoleRegisterService gameTencentMiniGameRoleRegisterService;

    @Autowired
    private IGameTencentMiniGameOrderSplitLogService gameTencentMiniGameOrderSplitLogService;

    @Override
    public ResultVO<OrderBackQueryRpcVO> orderBackQuery(TencentMiniGameOrderBackQueryRpcDTO dto) {
        log.error("微信小游戏订单媒体SDK回传结果查询：{}", JsonUtil.toString(dto));
        GameTencentMiniGameOrder orderLog = this.queryOrder(dto);
        if (orderLog == null) {
            try {
                Thread.sleep(15 * 1000L);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            orderLog = this.queryOrder(dto);
        }
        if (orderLog == null) {
            return ResultVO.ok(OrderBackQueryRpcVO.builder()
                    .doBack(Boolean.FALSE)
                    .backMsg("回传异常，找不到订单：" + dto.getOrderId())
                    .build());
        }
        List<Long> splitMoney = gameTencentMiniGameOrderSplitLogService.list(new LambdaQueryWrapper<GameTencentMiniGameOrderSplitLog>()
                .eq(GameTencentMiniGameOrderSplitLog::getOrderNo, orderLog.getOrderId())
                .eq(GameTencentMiniGameOrderSplitLog::getBackType, BackTypeEnum.BACK_MEDIA_SDK.getBackType())
                .orderByAsc(GameTencentMiniGameOrderSplitLog::getBackIndex)
        ).stream().map(GameTencentMiniGameOrderSplitLog::getSplitMoney).collect(Collectors.toList());
        return ResultVO.ok(OrderBackQueryRpcVO.builder()
                .doBack(BackStatusEnum.getByValue(orderLog.getBackStatus()) == BackStatusEnum.SUCCESS)
                .backMoney(CollectionUtils.isEmpty(splitMoney) ? Collections.singletonList(orderLog.getBackMoney()) : splitMoney)
                .backMsg(orderLog.getBackMsg())
                .build());
    }

    private GameTencentMiniGameOrder queryOrder(TencentMiniGameOrderBackQueryRpcDTO dto) {
        String lockKey = ServerInfo.SERVER_NAME + ":TencentMiniGameBack:" + dto.getGameId() + ":" + dto.getOrderId();
        int maxCount = 0;
        while (true) {
            if (redisTemplate.opsForValue().get(lockKey) == null) {
                break;
            }
            if (maxCount++ >= 120 / 10) {
                break;
            }
            try {
                Thread.sleep(10 * 1000L);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        return gameTencentMiniGameOrderService.getOne(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
                .eq(GameTencentMiniGameOrder::getOrderId, dto.getOrderId())
                .eq(GameTencentMiniGameOrder::getGameId, dto.getGameId())
                .eq(GameTencentMiniGameOrder::getAgentKey, dto.getAgentKey())
                .eq(GameTencentMiniGameOrder::getWechatOpenid, dto.getWechatOpenid())
                .eq(GameTencentMiniGameOrder::getBackType, BackTypeEnum.BACK_MEDIA_SDK.getBackType())
        );
    }

    @Override
    public ResultVO<Boolean> backOrder(TencentOrderDTO dto) {
        if (Objects.equals(OrderStatusEnum.SUCCESS_PAY.getValue(), dto.getOrderStatus())) {
            log.error("腾讯小游戏订单回传收到：{}。", JsonUtil.toString(dto));
        } else {
            log.error("腾讯小游戏订单回传收到：{}。订单未支付，直接过滤", JsonUtil.toString(dto));
            return ResultVO.ok(true);
        }
        boolean isFirstOrder = gameTencentMiniGameOrderService.getOne(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
                .select(GameTencentMiniGameOrder::getOrderId)
                .eq(GameTencentMiniGameOrder::getGameId, dto.getGameId())
                .eq(GameTencentMiniGameOrder::getWechatAppId, dto.getWechatAppId())
                .eq(GameTencentMiniGameOrder::getAdAccountId, dto.getAdAccountId())
                .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                .eq(GameTencentMiniGameOrder::getWechatOpenid, dto.getWechatOpenid())
                .eq(GameTencentMiniGameOrder::getBackType, BackTypeEnum.BACK_API.getBackType())
                .last("limit 1")) == null;
        GameTencentMiniGameUser userLog = gameTencentMiniGameUserService.getOne(new LambdaQueryWrapper<GameTencentMiniGameUser>()
                .select(GameTencentMiniGameUser::getBackStatus, GameTencentMiniGameUser::getClickId)
                .eq(GameTencentMiniGameUser::getGameId, dto.getGameId())
                .eq(GameTencentMiniGameUser::getWechatAppId, dto.getWechatAppId())
                .eq(GameTencentMiniGameUser::getWechatOpenid, dto.getWechatOpenid())
                .eq(GameTencentMiniGameUser::getAdAccountId, dto.getAdAccountId())
                .orderByDesc(GameTencentMiniGameUser::getCreateTime)
                .eq(GameTencentMiniGameUser::getBackType, BackTypeEnum.BACK_API.getBackType())
                .last("limit 1")
        );
        GameTencentMiniGameOrder orderLog = GameTencentMiniGameOrder.builder()
                .adAccountId(dto.getAdAccountId())
                .gameId(dto.getGameId())
                .orderId(dto.getOrderId())
                .agentKey(dto.getChannel())
                .rechargeMoney(dto.getRechargeMoney())
                .rechargeTime(dto.getRechargeTime())
                .subscribeTime(dto.getSubscribeTime())
                .registerTime(dto.getRegisterTime())
                .wechatAppId(dto.getWechatAppId())
                .wechatOpenid(dto.getWechatOpenid())
                .orderStatus(dto.getOrderStatus())
                .payTime(dto.getPayTime())
                .createTime(LocalDateTime.now())
                .backStatus(BackStatusEnum.NO.getBackStatus())
                .backPolicyId(dto.getBackPolicyId())
                .clickId(userLog == null ? null : userLog.getClickId())
                .roleId(dto.getRoleId())
                .roleName(dto.getRoleName())
                .isFirstOrder(isFirstOrder)
                .backType(BackTypeEnum.BACK_API.getBackType())
                .build();
        gameTencentMiniGameOrderService.save(orderLog);
        if (userLog == null) {
            log.error("腾讯小游戏订单回传失败，找不到回传的用户 orderId: {}", orderLog.getOrderId());
            return ResultVO.fail("找不到回传用户");
        } else {
            return ResultVO.ok(gameTencentMiniGameOrderService.orderBack(orderLog));
        }
    }

    @Override
    public ResultVO<Boolean> callBackOrder(TencentOrderDTO dto) {
        if (Objects.equals(OrderStatusEnum.SUCCESS_PAY.getValue(), dto.getOrderStatus())) {
            log.error("腾讯小游戏订单媒体SDK回传收到：{}。", JsonUtil.toString(dto));
        } else {
            log.error("腾讯小游戏订单媒体SDK回传收到：{}。订单未支付，直接过滤", JsonUtil.toString(dto));
            return ResultVO.ok(true);
        }
        // 此处加锁防止 cp 方调用过快，导致查询回传结果时判断逻辑没走完
        String lockKey = ServerInfo.SERVER_NAME + ":TencentMiniGameOrderBack:" + dto.getGameId() + ":" + dto.getOrderId();
        redisTemplate.opsForValue().set(lockKey, dto.getOrderId(), 2L, TimeUnit.MINUTES);
        try {
            boolean isFirstOrder = gameTencentMiniGameOrderService.getOne(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
                    .select(GameTencentMiniGameOrder::getOrderId)
                    .eq(GameTencentMiniGameOrder::getGameId, dto.getGameId())
                    .eq(GameTencentMiniGameOrder::getWechatAppId, dto.getWechatAppId())
                    .eq(GameTencentMiniGameOrder::getAdAccountId, dto.getAdAccountId())
                    .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
                    .eq(GameTencentMiniGameOrder::getWechatOpenid, dto.getWechatOpenid())
                    .eq(GameTencentMiniGameOrder::getBackType, BackTypeEnum.BACK_MEDIA_SDK.getBackType())
                    .last("limit 1")) == null;
            GameTencentMiniGameOrder orderLog = GameTencentMiniGameOrder.builder()
                    .adAccountId(dto.getAdAccountId())
                    .gameId(dto.getGameId())
                    .orderId(dto.getOrderId())
                    .agentKey(dto.getChannel())
                    .rechargeMoney(dto.getRechargeMoney())
                    .rechargeTime(dto.getRechargeTime())
                    .subscribeTime(dto.getSubscribeTime())
                    .registerTime(dto.getRegisterTime())
                    .wechatAppId(dto.getWechatAppId())
                    .wechatOpenid(dto.getWechatOpenid())
                    .orderStatus(dto.getOrderStatus())
                    .payTime(dto.getPayTime())
                    .createTime(LocalDateTime.now())
                    .backStatus(BackStatusEnum.NO.getBackStatus())
                    .backPolicyId(dto.getBackPolicyId())
                    .roleId(dto.getRoleId())
                    .roleName(dto.getRoleName())
                    .isFirstOrder(isFirstOrder)
                    .backType(BackTypeEnum.BACK_MEDIA_SDK.getBackType())
                    .build();
            gameTencentMiniGameOrderService.save(orderLog);
            return ResultVO.ok(gameTencentMiniGameOrderService.callback(orderLog));
        } finally {
            redisTemplate.delete(lockKey);
        }
    }

    @Override
    public ResultVO<Boolean> backUser(TencentUserDTO dto) {
        log.error("腾讯小游戏用户回传收到：{}", JsonUtil.toString(dto));
        GameTencentMiniGameUser userLog = GameTencentMiniGameUser.builder()
                .adAccountId(dto.getAdAccountId())
                .gameId(dto.getGameId())
                .backPolicyId(dto.getBackPolicyId())
                .agentKey(dto.getChannel())
                .subscribeTime(dto.getSubscribeTime())
                .registerTime(dto.getRegisterTime())
                .wechatAppId(dto.getWechatAppId())
                .wechatOpenid(dto.getWechatOpenid())
                .backStatus(BackStatusEnum.NO.getBackStatus())
                .clickId(dto.getClickId())
                .createTime(LocalDateTime.now())
                .backType(BackTypeEnum.BACK_API.getBackType())
                .build();
        //匹配回传URL
        String callBackUrl = gameTencentMiniGameCallbackService.getCallBackUrl(dto.getGameId(), dto.getWechatOpenid(),
                dto.getClickId(), dto.getRegisterTime(), true);
        if (Strings.isNotBlank(callBackUrl)) {
            userLog.setCallBackUrl(callBackUrl);
        }
        //保存数据
        gameTencentMiniGameUserService.save(userLog);
        //查询回传策略
        GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(dto.getBackPolicyId());
        //判断是否开启激活回传开关
        if (gameBackPolicy != null && Objects.equals(gameBackPolicy.getActiveBackSwitch(), Boolean.TRUE)) {
            //激活回传
            gameTencentMiniGameUserService.userBack(userLog);
        }
        return ResultVO.ok(Boolean.TRUE);
    }

    public ResultVO<Boolean> callBackUser(TencentUserDTO dto) {
        log.error("腾讯小游戏用户媒体SDK回传收到：{}", JsonUtil.toString(dto));
        GameTencentMiniGameUser userLog = GameTencentMiniGameUser.builder()
                .adAccountId(dto.getAdAccountId())
                .gameId(dto.getGameId())
                .backPolicyId(dto.getBackPolicyId())
                .agentKey(dto.getChannel())
                .subscribeTime(dto.getSubscribeTime())
                .registerTime(dto.getRegisterTime())
                .wechatAppId(dto.getWechatAppId())
                .wechatOpenid(dto.getWechatOpenid())
                .backStatus(BackStatusEnum.NO.getBackStatus())
                .clickId(dto.getClickId())
                .createTime(LocalDateTime.now())
                .backType(BackTypeEnum.BACK_MEDIA_SDK.getBackType())
                .build();
        gameTencentMiniGameUserService.save(userLog);
        return ResultVO.ok(gameTencentMiniGameUserService.callback(userLog));
    }

    @Override
    public ResultVO<Boolean> backRoleRegister(TencentRoleRegisterRpcDTO dto) {
        log.error("腾讯小游戏创角回传收到：{}", JsonUtil.toString(dto));
        GameTencentMiniGameRoleRegister roleRegisterLog;
        GameTencentMiniGameRoleRegister oldRole = gameTencentMiniGameRoleRegisterService.getOne(new LambdaQueryWrapper<GameTencentMiniGameRoleRegister>()
                .eq(GameTencentMiniGameRoleRegister::getGameId, dto.getGameId())
                .eq(GameTencentMiniGameRoleRegister::getWechatAppId, dto.getWechatAppId())
                .eq(GameTencentMiniGameRoleRegister::getWechatOpenid, dto.getWechatOpenid())
                .eq(GameTencentMiniGameRoleRegister::getRoleId, dto.getRoleId())
                .eq(GameTencentMiniGameRoleRegister::getBackType, BackTypeEnum.BACK_API.getBackType())
                .last("limit 1")
        );
        if (oldRole != null) {
            roleRegisterLog = oldRole;
            if (dto.getRoleLevel() != null && (oldRole.getRoleLevel() == null || oldRole.getRoleLevel() < dto.getRoleLevel())) {
                gameTencentMiniGameRoleRegisterService.update(new LambdaUpdateWrapper<GameTencentMiniGameRoleRegister>()
                        .set(GameTencentMiniGameRoleRegister::getRoleLevel, dto.getRoleLevel())
                        .set(GameTencentMiniGameRoleRegister::getRoleName, dto.getRoleName())
                        .eq(GameTencentMiniGameRoleRegister::getId, oldRole.getId())
                );
            }
            // 创角已回传
            if (Objects.equals(oldRole.getBackStatus(), BackStatusEnum.SUCCESS.getBackStatus())) {
                //判断是否完成新手引导回传, 若没有, 则执行新手引导回传
                if (!Objects.equals(oldRole.getTutorialFinishBackStatus(), BackStatusEnum.SUCCESS.getBackStatus())) {
                    //回传策略
                    GameBackPolicy gameBackPolicy = oldRole.getBackPolicyId() == null ? null : gameBackPolicyService.getById(roleRegisterLog.getBackPolicyId());
                    //新手引导回传, 设置最新等级
                    oldRole.setRoleLevel(dto.getRoleLevel());
                    gameTencentMiniGameRoleRegisterService.tutorialFinishBack(oldRole, gameBackPolicy);
                }
                // 创角已回传, 不重复执行回传
                return ResultVO.ok(true);
            }
        } else {
            GameTencentMiniGameUser userLog = gameTencentMiniGameUserService.getOne(new LambdaQueryWrapper<GameTencentMiniGameUser>()
                    .select(GameTencentMiniGameUser::getBackStatus, GameTencentMiniGameUser::getClickId)
                    .eq(GameTencentMiniGameUser::getGameId, dto.getGameId())
                    .eq(GameTencentMiniGameUser::getWechatAppId, dto.getWechatAppId())
                    .eq(GameTencentMiniGameUser::getWechatOpenid, dto.getWechatOpenid())
                    .eq(GameTencentMiniGameUser::getAdAccountId, dto.getAdAccountId())
                    .eq(GameTencentMiniGameUser::getBackType, BackTypeEnum.BACK_API.getBackType())
                    .orderByDesc(GameTencentMiniGameUser::getCreateTime)
                    .last("limit 1")
            );
            roleRegisterLog = GameTencentMiniGameRoleRegister.builder()
                    .backPolicyId(dto.getBackPolicyId())
                    .agentKey(dto.getChannel())
                    .gameId(dto.getGameId())
                    .adAccountId(dto.getAdAccountId())
                    .wechatAppId(dto.getWechatAppId())
                    .wechatOpenid(dto.getWechatOpenid())
                    .clickId(userLog == null ? null : userLog.getClickId())
                    .registerTime(dto.getRegisterTime())
                    .backStatus(BackStatusEnum.NO.getBackStatus())
                    .createTime(LocalDateTime.now())
                    .roleId(dto.getRoleId())
                    .roleName(dto.getRoleName())
                    .roleLevel(dto.getRoleLevel())
                    .backType(BackTypeEnum.BACK_API.getBackType())
                    .build();
            gameTencentMiniGameRoleRegisterService.save(roleRegisterLog);
        }
        return ResultVO.ok(gameTencentMiniGameRoleRegisterService.roleRegisterBack(roleRegisterLog));
    }

    @Override
    public ResultVO<Boolean> callBackRole(TencentRoleRegisterRpcDTO dto) {
        log.error("腾讯小游戏创角媒体SDK回传收到：{}", JsonUtil.toString(dto));
        GameTencentMiniGameRoleRegister roleRegisterLog;
        GameTencentMiniGameRoleRegister oldRole = gameTencentMiniGameRoleRegisterService.getOne(new LambdaQueryWrapper<GameTencentMiniGameRoleRegister>()
                .eq(GameTencentMiniGameRoleRegister::getGameId, dto.getGameId())
                .eq(GameTencentMiniGameRoleRegister::getWechatAppId, dto.getWechatAppId())
                .eq(GameTencentMiniGameRoleRegister::getWechatOpenid, dto.getWechatOpenid())
                .eq(GameTencentMiniGameRoleRegister::getRoleId, dto.getRoleId())
                .eq(GameTencentMiniGameRoleRegister::getBackType, BackTypeEnum.BACK_MEDIA_SDK.getBackType())
                .last("limit 1")
        );
        if (oldRole != null) {
            roleRegisterLog = oldRole;
            if (dto.getRoleLevel() != null && (oldRole.getRoleLevel() == null || oldRole.getRoleLevel() < dto.getRoleLevel())) {
                gameTencentMiniGameRoleRegisterService.update(new LambdaUpdateWrapper<GameTencentMiniGameRoleRegister>()
                        .set(GameTencentMiniGameRoleRegister::getRoleLevel, dto.getRoleLevel())
                        .set(GameTencentMiniGameRoleRegister::getRoleName, dto.getRoleName())
                        .eq(GameTencentMiniGameRoleRegister::getId, oldRole.getId())
                );
            }
            // 创角已回传, 不重复执行回传
            if (Objects.equals(oldRole.getBackStatus(), BackStatusEnum.SUCCESS.getBackStatus())) {
                return ResultVO.ok(Boolean.TRUE);
            }
        } else {
            GameTencentMiniGameUser userLog = gameTencentMiniGameUserService.getOne(new LambdaQueryWrapper<GameTencentMiniGameUser>()
                    .select(GameTencentMiniGameUser::getBackStatus, GameTencentMiniGameUser::getClickId)
                    .eq(GameTencentMiniGameUser::getGameId, dto.getGameId())
                    .eq(GameTencentMiniGameUser::getWechatAppId, dto.getWechatAppId())
                    .eq(GameTencentMiniGameUser::getWechatOpenid, dto.getWechatOpenid())
                    .eq(GameTencentMiniGameUser::getAdAccountId, dto.getAdAccountId())
                    .eq(GameTencentMiniGameUser::getBackType, BackTypeEnum.BACK_MEDIA_SDK.getBackType())
                    .orderByDesc(GameTencentMiniGameUser::getCreateTime)
                    .last("limit 1")
            );
            roleRegisterLog = GameTencentMiniGameRoleRegister.builder()
                    .backPolicyId(dto.getBackPolicyId())
                    .agentKey(dto.getChannel())
                    .gameId(dto.getGameId())
                    .adAccountId(dto.getAdAccountId())
                    .wechatAppId(dto.getWechatAppId())
                    .wechatOpenid(dto.getWechatOpenid())
                    .clickId(userLog == null ? null : userLog.getClickId())
                    .registerTime(dto.getRegisterTime())
                    .backStatus(BackStatusEnum.NO.getBackStatus())
                    .createTime(LocalDateTime.now())
                    .roleId(dto.getRoleId())
                    .roleName(dto.getRoleName())
                    .roleLevel(dto.getRoleLevel())
                    .backType(BackTypeEnum.BACK_MEDIA_SDK.getBackType())
                    .build();
            gameTencentMiniGameRoleRegisterService.save(roleRegisterLog);
        }
        return ResultVO.ok(gameTencentMiniGameRoleRegisterService.callback(roleRegisterLog));
    }

    @Override
    public ResultVO<Map<String, String>> getCallBackByOpenId(Long gameId, String wechatOpenid) {
        Map<String, String> map = null;
        try {
            map = gameTencentMiniGameCallbackService.getCallBackByOpenId(gameId, wechatOpenid);
        } catch (Exception e) {
            log.error("微信小游投腾讯匹配监测链接异常, gameId : {}, wechatOpenid : {}, e : {} ",
                    gameId, wechatOpenid, e.getMessage(), e);
        }
        return ResultVO.ok(map);
    }
}
