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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.sd4324530.jtuple.Tuple2;
import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
import com.zanxiang.game.back.serve.dao.mapper.GameTencentMiniGameBackLogMapper;
import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameBackLog;
import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameOrder;
import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameRoleRegister;
import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameUser;
import com.zanxiang.game.back.serve.pojo.enums.ActionTypeEnum;
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.IGameTencentMiniGameBackLogService;
import com.zanxiang.game.back.serve.service.IGameTencentMiniGameCallbackService;
import com.zanxiang.game.back.serve.service.IGameTencentMiniGameUserService;
import com.zanxiang.module.util.DateUtil;
import com.zanxiang.module.util.JsonUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

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

@Slf4j
@Service
public class GameTencentMiniGameBackLogServiceImpl extends ServiceImpl<GameTencentMiniGameBackLogMapper, GameTencentMiniGameBackLog>
        implements IGameTencentMiniGameBackLogService {
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IGameTencentMiniGameUserService gameTencentMiniGameUserService;

    @Autowired
    private IGameTencentMiniGameCallbackService gameTencentMiniGameCallbackService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Tuple2<BackStatusEnum, String> userAndRoleRegisterBack(GameTencentMiniGameUser userLog) {
        //注册回传
        Tuple2<BackStatusEnum, String> userBackResult = this.userBack(userLog);
        //构造创角回传
        try {
            GameTencentMiniGameBackLog backLog = GameTencentMiniGameBackLog.builder()
                    .gameId(userLog.getGameId())
                    .adAccountId(userLog.getAdAccountId())
                    .clickId(userLog.getClickId())
                    .actionTime(userLog.getRegisterTime())
                    .wechatOpenid(userLog.getWechatOpenid())
                    .wechatAppId(userLog.getWechatAppId())
                    .actionType(ActionTypeEnum.CREATE_ROLE.getActionType())
                    .createTime(LocalDateTime.now())
                    .backType(BackTypeEnum.BACK_API.getBackType())
                    .build();
            Tuple2<BackStatusEnum, String> backResult = callback(backLog);
            backLog.setBackStatus(backResult.first.getBackStatus());
            backLog.setErrMsg(backResult.second);
            save(backLog);
        } catch (Exception ignored) {
        }
        //返回注册回传结果
        return userBackResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Tuple2<BackStatusEnum, String> userBack(GameTencentMiniGameUser userLog) {
        GameTencentMiniGameBackLog backLog = GameTencentMiniGameBackLog.builder()
                .gameId(userLog.getGameId())
                .adAccountId(userLog.getAdAccountId())
                .clickId(userLog.getClickId())
                .actionTime(LocalDateTime.now())
                .wechatOpenid(userLog.getWechatOpenid())
                .wechatAppId(userLog.getWechatAppId())
                .actionType(ActionTypeEnum.REGISTER.getActionType())
                .createTime(LocalDateTime.now())
                .backType(BackTypeEnum.BACK_API.getBackType())
                .build();
        Tuple2<BackStatusEnum, String> backResult = callback(backLog);
        backLog.setBackStatus(backResult.first.getBackStatus());
        backLog.setErrMsg(backResult.second);
        save(backLog);
        return backResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Tuple2<BackStatusEnum, String> orderBack(GameTencentMiniGameOrder orderLog, LocalDateTime backTime, Long backMoney) {
        String actionType = orderLog.getOrderStatus().equals(OrderStatusEnum.SUCCESS_PAY.getValue()) ?
                ActionTypeEnum.PURCHASE.getActionType() : ActionTypeEnum.COMPLETE_ORDER.getActionType();
        GameTencentMiniGameBackLog backLog = GameTencentMiniGameBackLog.builder()
                .gameId(orderLog.getGameId())
                .adAccountId(orderLog.getAdAccountId())
                .clickId(orderLog.getClickId())
                .actionTime(backTime)
                .wechatOpenid(orderLog.getWechatOpenid())
                .wechatAppId(orderLog.getWechatAppId())
                .actionType(actionType)
                .amount(backMoney)
                .orderId(orderLog.getOrderId())
                .createTime(LocalDateTime.now())
                .backType(BackTypeEnum.BACK_API.getBackType())
                .build();
        Tuple2<BackStatusEnum, String> backResult = callback(backLog);
        backLog.setBackStatus(backResult.first.getBackStatus());
        backLog.setErrMsg(backResult.second);
        save(backLog);
        return backResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Tuple2<BackStatusEnum, String> roleRegisterBack(GameTencentMiniGameRoleRegister roleRegisterLog) {
        GameTencentMiniGameBackLog backLog = GameTencentMiniGameBackLog.builder()
                .gameId(roleRegisterLog.getGameId())
                .adAccountId(roleRegisterLog.getAdAccountId())
                .clickId(roleRegisterLog.getClickId())
                .actionTime(roleRegisterLog.getRegisterTime())
                .wechatOpenid(roleRegisterLog.getWechatOpenid())
                .wechatAppId(roleRegisterLog.getWechatAppId())
                .actionType(ActionTypeEnum.CREATE_ROLE.getActionType())
                .createTime(LocalDateTime.now())
                .backType(BackTypeEnum.BACK_API.getBackType())
                .build();
        Tuple2<BackStatusEnum, String> backResult = callback(backLog);
        backLog.setBackStatus(backResult.first.getBackStatus());
        backLog.setErrMsg(backResult.second);
        save(backLog);
        return backResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Tuple2<BackStatusEnum, String> tutorialFinishBack(GameTencentMiniGameRoleRegister roleRegisterLog) {
        GameTencentMiniGameBackLog backLog = GameTencentMiniGameBackLog.builder()
                .gameId(roleRegisterLog.getGameId())
                .adAccountId(roleRegisterLog.getAdAccountId())
                .clickId(roleRegisterLog.getClickId())
                .actionTime(roleRegisterLog.getRegisterTime())
                .wechatOpenid(roleRegisterLog.getWechatOpenid())
                .wechatAppId(roleRegisterLog.getWechatAppId())
                .actionType(ActionTypeEnum.TUTORIAL_FINISH.getActionType())
                .createTime(LocalDateTime.now())
                .backType(BackTypeEnum.BACK_API.getBackType())
                .build();
        Tuple2<BackStatusEnum, String> backResult = callback(backLog);
        backLog.setBackStatus(backResult.first.getBackStatus());
        backLog.setErrMsg(backResult.second);
        save(backLog);
        return backResult;
    }

    private Tuple2<BackStatusEnum, String> callback(GameTencentMiniGameBackLog backLog) {
        Map<String, Object> actionParam = null;
        if (backLog.getAmount() != null) {
            actionParam = new HashMap<>(2);
            actionParam.put("value", backLog.getAmount());
        }
        TencentMiniGameBackRequest request = TencentMiniGameBackRequest.builder()
                .actions(Collections.singletonList(TencentMiniGameBackRequest.Action.builder()
                        .action_time(DateUtil.localDateTimeToSecond(backLog.getActionTime()))
                        .user_id(TencentMiniGameBackRequest.UserId.builder().wechat_app_id(backLog.getWechatAppId()).wechat_openid(backLog.getWechatOpenid()).build())
                        .trace(TencentMiniGameBackRequest.Trace.builder().click_id(backLog.getClickId()).build())
                        .account_id(backLog.getAdAccountId())
                        .action_set_id(null)
                        .action_type(backLog.getActionType())
                        .action_param(actionParam)
                        .build()))
                .build();
        try {
            log.error("腾讯小游戏回传参数：{}", JsonUtil.toString(request));
            String callBackUrl = this.getCallBackUrl(backLog);
            if (Strings.isBlank(callBackUrl)) {
                return Tuple2.with(BackStatusEnum.FAILED, "监测链接未匹配到callBackUrl");
            }
            ResponseEntity<Map> response = restTemplate.postForEntity(callBackUrl, request, Map.class);
            log.error("腾讯小游戏回传完成：{}", JsonUtil.toString(response.getBody()));
            if (response.getStatusCode().is2xxSuccessful()) {
                if (Objects.equals(response.getBody().get("code").toString(), "0")) {
                    return Tuple2.with(BackStatusEnum.SUCCESS, null);
                }
            }
            return Tuple2.with(BackStatusEnum.FAILED, JsonUtil.toString(response.getBody()));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Tuple2.with(BackStatusEnum.FAILED, e.getMessage());
        }
    }

    private String getCallBackUrl(GameTencentMiniGameBackLog backLog) {
        GameTencentMiniGameUser gameTencentMiniGameUser = gameTencentMiniGameUserService.getOne(
                new LambdaQueryWrapper<GameTencentMiniGameUser>()
                        .eq(GameTencentMiniGameUser::getGameId, backLog.getGameId())
                        .eq(GameTencentMiniGameUser::getWechatAppId, backLog.getWechatAppId())
                        .eq(GameTencentMiniGameUser::getWechatOpenid, backLog.getWechatOpenid())
                        .eq(GameTencentMiniGameUser::getAdAccountId, backLog.getAdAccountId())
                        .eq(GameTencentMiniGameUser::getBackType, BackTypeEnum.BACK_API.getBackType())
                        .orderByDesc(GameTencentMiniGameUser::getCreateTime)
                        .last("limit 1"));
        String callBackUrl = Optional.ofNullable(gameTencentMiniGameUser)
                .map(GameTencentMiniGameUser::getCallBackUrl)
                .orElse(null);
        if (Strings.isNotBlank(callBackUrl) || gameTencentMiniGameUser == null) {
            return callBackUrl;
        }
        //再次查询回传URL, 抛开时间限制条件, 腾讯坑爹监测数据有可能延迟
        callBackUrl = gameTencentMiniGameCallbackService.getCallBackUrl(gameTencentMiniGameUser.getGameId(),
                gameTencentMiniGameUser.getWechatOpenid(), gameTencentMiniGameUser.getClickId(),
                gameTencentMiniGameUser.getRegisterTime(), false);
        //回传url更新到用户信息中
        if (Strings.isNotBlank(callBackUrl)) {
            gameTencentMiniGameUser.setCallBackUrl(callBackUrl);
            gameTencentMiniGameUserService.updateById(gameTencentMiniGameUser);
        }
        return callBackUrl;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public static class TencentMiniGameBackRequest {

        private List<Action> actions;

        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        @Builder
        public static class Action {

            private Long action_time;

            private UserId user_id;
            private Trace trace;

            private Long account_id;

            private Long action_set_id;

            private String action_type;

            private Map<String, Object> action_param;
        }

        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        @Builder
        public static class UserId {

            private String wechat_app_id;

            private String wechat_openid;

        }

        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        @Builder
        public static class Trace {
            private String click_id;
        }
    }
}
