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

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
import com.zanxiang.game.module.base.pojo.enums.GameCategoryEnum;
import com.zanxiang.game.module.mybatis.entity.*;
import com.zanxiang.game.module.mybatis.mapper.OrderMapper;
import com.zanxiang.game.module.sdk.enums.KafkaEventTrackEnum;
import com.zanxiang.game.module.sdk.pojo.dto.GamePayWayDTO;
import com.zanxiang.game.module.sdk.pojo.dto.PlatformOrderDTO;
import com.zanxiang.game.module.sdk.pojo.param.ProductPayParam;
import com.zanxiang.game.module.sdk.pojo.param.UserData;
import com.zanxiang.game.module.sdk.service.*;
import com.zanxiang.module.util.JsonUtil;
import com.zanxiang.module.util.bean.BeanUtil;
import com.zanxiang.module.util.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

/**
 * 平台订单逻辑开发
 *
 * @author xufeng
 * @date 2022-06-06 17:06
 */
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {

    @Autowired
    private IGameService gameService;

    @Autowired
    private IKafkaService kafkaService;

    @Autowired
    private IGameUserService gameUserService;

    @Autowired
    private IGameUserRoleService gameUserRoleService;

    @Autowired
    private IGamePayWayService gamePayWayService;

    @Autowired
    private ICallBackService callBackService;

    @Autowired
    private IGameSupperService gameSupperService;

    @Autowired
    private IUserRechargeWhiteService userRechargeWhiteService;

    @Override
    @Transactional(rollbackFor = {Exception.class, RuntimeException.class})
    public Boolean createOrder(ProductPayParam payParam, User user, UserData userData) {
        //游戏id
        Long gameId = userData.getGameId();
        //游戏信息
        Game game = gameService.getById(gameId);
        if (Objects.equals(game.getRechargeCloseSwitch(), Boolean.TRUE)) {
            this.rechargeCloseCheck(game, user);
        }
        //玩家信息
        GameUser gameUser = gameUserService.getOne(new LambdaQueryWrapper<GameUser>()
                .eq(GameUser::getUserId, userData.getUserId()));
        //角色信息
        GameUserRole gameUserRole = gameUserRoleService.getOne(new LambdaQueryWrapper<GameUserRole>()
                .eq(GameUserRole::getGameId, gameId)
                .eq(GameUserRole::getUserId, userData.getUserId())
                .eq(GameUserRole::getRoleId, payParam.getRoleId()));
        if (gameUser == null || gameUserRole == null) {
            log.error("游戏用户信息不全, game : {}, gameUser : {}, gameUserRole : {}", JsonUtil.toString(game),
                    JsonUtil.toString(gameUser), JsonUtil.toString(gameUserRole));
            throw new BaseException("参数错误, 游戏用户信息不全");
        }
        //游戏支付配置信息
        GamePayWayDTO gamePayWayDTO = gamePayWayService.getGamePayWay(gameId, payParam.getPayWay(), payParam.getPayDevice());
        //生成订单id
        String orderNum = this.getOrderNum(userData.getUserId());
        //构造订单
        Order order = this.transform(userData, orderNum, payParam, user, gameUser, game, gameUserRole, gamePayWayDTO);
        super.save(order);
        //设置订单号
        payParam.setOrderId(orderNum);
        //订单回传
        callBackService.orderCallBack(BeanUtil.copy(order, PlatformOrderDTO.class));
        //下单数据埋点发送到卡夫卡
        kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ORDER_CREATE, JsonUtil.toString(order));
        //返回
        return Boolean.TRUE;
    }

    private void rechargeCloseCheck(Game game, User user) {
        //白名单过滤
        if (userRechargeWhiteService.count(new LambdaQueryWrapper<UserRechargeWhite>()
                .eq(UserRechargeWhite::getGameId, game.getId())
                .eq(UserRechargeWhite::getUserId, user.getId())
        ) > 0) {
            return;
        }
        throw new BaseException("游戏已经关闭充值, 请联系客服!");
    }

    private Order transform(UserData userData, String orderNum, ProductPayParam payParam, User user, GameUser gameUser,
                            Game game, GameUserRole gameUserRole, GamePayWayDTO gamePayWayDTO) {
        Order order = Order.builder()
                .orderId(orderNum)
                .cpOrderId(payParam.getOrderId())
                .agentId(user.getAgentId())
                .cpId(game.getCpId())
                .userId(userData.getUserId())
                .mgUserId(gameUser.getId())
                .regTime(user.getCreateTime())
                .gameId(userData.getGameId())
                .roleId(gameUserRole.getRoleId())
                .roleName(gameUserRole.getRoleName())
                .roleLevel(gameUserRole.getRoleLevel())
                .roleVipLevel(gameUserRole.getRoleVipLevel())
                .serverId(gameUserRole.getServerId())
                .serverName(gameUserRole.getServerName())
                .amount(payParam.getAmount())
                .productId(payParam.getProductId())
                .productName(payParam.getProductName())
                .deviceSystem(userData.getDeviceSystem())
                .payWayId(gamePayWayDTO.getPayWayId())
                .payDeviceId(gamePayWayDTO.getPayDeviceId())
                .gamePayWayId(gamePayWayDTO.getId())
                .ext(payParam.getExtension())
                .status(OrderStatusEnum.READY_PAY.getValue())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();
        //sdk前端存在bug, 可能将系统订单id作为CP订单id传上来的情况, 怀疑前端缓存问题导致, 这里参数修正
        GameSupper gameSupper = gameSupperService.getById(game.getSuperGameId());
        if (gameSupper == null) {
            return order;
        }
        //蜀山天下CP订单id修正, 蜀山天下订单前缀固定为: NZW
        if (Objects.equals(gameSupper.getId(), 8L) && !order.getCpOrderId().contains("NZW")) {
            if (Strings.isNotBlank(order.getExt()) && order.getExt().contains("NZW")) {
                order.setCpOrderId(order.getExt());
            }
        }
        //梦回白玉京CP订单id修正, ext字段中传的订单id
        if (Objects.equals(gameSupper.getId(), 11L) && Strings.isNotBlank(order.getExt())
                && !Objects.equals(order.getCpOrderId(), order.getExt())) {
            order.setCpOrderId(order.getExt());
        }
        //仙剑安卓APP端CP订单id修正, ext字段中包含了订单id
        if (Objects.equals(gameSupper.getId(), 12L) && Strings.isNotBlank(order.getExt())
                && Objects.equals(game.getCategory(), GameCategoryEnum.CATEGORY_APP.getId())) {
            //解析订单id, 若订单中的CP订单id不对, 则修正
            String cpOrderId = null;
            try {
                cpOrderId = JSONObject.parse(order.getExt()).getString("orderId");
            } catch (Exception ignored) {
            }
            if (Strings.isNotBlank(cpOrderId) && !Objects.equals(cpOrderId, order.getCpOrderId())) {
                order.setCpOrderId(cpOrderId);
            }
        }
        return order;
    }

    @Override
    public String getOrderNum(Long userId) {
        //时间（精确到毫秒）
        DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        String localDate = LocalDateTime.now().format(ofPattern);
        //3位随机数
        String randomNumeric = RandomStringUtils.randomNumeric(3);
        //5位用户id
        int subStrLength = 5;
        String sUserId = userId.toString();
        int length = sUserId.length();
        String str;
        if (length >= subStrLength) {
            str = sUserId.substring(length - subStrLength, length);
        } else {
            str = String.format("%0" + subStrLength + "d", userId);
        }
        return localDate + str + randomNumeric;
    }

    @Override
    public PlatformOrderDTO getByOrderId(String orderId) {
        Order order = getOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderId, orderId));
        return BeanUtil.copy(order, PlatformOrderDTO.class);
    }
}
