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

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.mybatis.entity.*;
import com.zanxiang.game.module.mybatis.mapper.GameUserRoleMapper;
import com.zanxiang.game.module.sdk.constant.RedisKeyConstant;
import com.zanxiang.game.module.sdk.enums.DataTypeEnum;
import com.zanxiang.game.module.sdk.enums.KafkaEventTrackEnum;
import com.zanxiang.game.module.sdk.enums.LoginTypeEnum;
import com.zanxiang.game.module.sdk.pojo.param.GameRoleActiveCallParam;
import com.zanxiang.game.module.sdk.pojo.param.GameUserRoleSubmitParam;
import com.zanxiang.game.module.sdk.pojo.param.GameUserRoleUpdateParam;
import com.zanxiang.game.module.sdk.pojo.param.UserData;
import com.zanxiang.game.module.sdk.service.*;
import com.zanxiang.module.redis.service.IDistributedLockComponent;
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.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import reactor.util.function.Tuple2;

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

/**
 * @author : xufeng
 * @time : 2022-07-06
 */
@Slf4j
@Service
public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, GameUserRole> implements IGameUserRoleService {

    @Value("${server.domain}")
    private String serverUrl;

    @Autowired
    private IUserService userService;

    @Autowired
    private IKafkaService kafkaService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IGameUserService gameUserService;

    @Autowired
    private ICallBackService callBackService;

    @Autowired
    private IUserTokenService userTokenService;

    @Autowired
    private IUserLoginLogService userLoginLogService;

    @Autowired
    private IDistributedLockComponent distributedLockComponent;

    @Autowired
    private IPushMsgService pushMsgService;

    @Autowired
    private IGameExtService gameExtService;

    @Autowired
    private IRoleOperateService roleOperateService;

    @Override
    public Boolean updateUserGameRole(GameUserRoleSubmitParam param) {
        //查询游戏信息
        GameExt gameExt = gameExtService.getByGameAppId(param.getGameId());
        if (gameExt == null || Strings.isBlank(gameExt.getLoginKey())) {
            log.error("参数错误, 游戏信息不存在, param : {}", JsonUtil.toString(param));
            throw new BaseException("参数错误, 游戏信息不存在");
        }
        //根据token检验
        UserToken userToken = userTokenService.getCheckUserToken(param.getUserId(), param.getToken());
        if (userToken == null) {
            log.error("参数错误, token令牌无效, param : {}", JsonUtil.toString(param));
            throw new BaseException("参数错误, token令牌无效");
        }
        //验证签名
        Tuple2<String, String> tuple2 = userTokenService.getMySign(gameExt, param.getUserId(), param.getToken());
        if (!Objects.equals(tuple2.getT2(), param.getSign())) {
            log.error("参数错误 , str : {}, mySign : {}, sign : {}", tuple2.getT1(), tuple2.getT2(), param.getSign());
            throw new BaseException("参数错误, sign验证失败");
        }
        //提交的角色信息
        GameUserRoleUpdateParam gameUserRoleParam = param.getGameUserRoleParam();
        //查询玩家信息, 调用方的userId不准确, 可能是导量的小程序userId
        User user = userService.getById(userToken.getUserId());
        //构建 userData
        UserData userData = new UserData();
        userData.setUserId(user.getId());
        userData.setGameId(user.getGameId());
        userData.setDeviceSystem(param.getOs());
        //判断角色是否存在
        GameUserRole gameUserRole = super.getOne(new LambdaQueryWrapper<GameUserRole>()
                .eq(GameUserRole::getUserId, user.getId())
                .eq(GameUserRole::getGameId, user.getGameId())
                .eq(GameUserRole::getRoleId, gameUserRoleParam.getRoleId()));
        //更新游戏角色
        if (gameUserRole != null) {
            //角色更新
            return this.gameRoleUpdate(gameUserRoleParam, gameUserRole, userData);
        }
        //新建游戏角色
        boolean result = this.gameRoleCreate(gameUserRoleParam, userData);
        if (!result) {
            return Boolean.FALSE;
        }
        //创建角色通知监听服务
        this.callListenIn(gameUserRoleParam, userData);
        //返回结果
        return Boolean.TRUE;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateUserGameRole(GameUserRoleUpdateParam param, UserData userData) {
        //上报类型
        Integer dataType = param.getDataType();
        //选择服务器
        if (Objects.equals(dataType, DataTypeEnum.TYPE_SELECT_SERVER.getDateType())) {
            return Boolean.TRUE;
        }
        //创建角色
        if (Objects.equals(dataType, DataTypeEnum.TYPE_CREATE_ROLE.getDateType())) {
            //新建游戏角色
            boolean result = this.gameRoleCreate(param, userData);
            if (result) {
                //插入用户登录记录
                userLoginLogService.createRoleLoginLog(userData, param, LoginTypeEnum.LOGIN_IN);
            }
            return result;
        }
        //判断角色是否存在
        GameUserRole gameUserRole = super.getOne(new LambdaQueryWrapper<GameUserRole>()
                .eq(GameUserRole::getUserId, userData.getUserId())
                .eq(GameUserRole::getGameId, userData.getGameId())
                .eq(GameUserRole::getRoleId, param.getRoleId()));
        //逻辑兜底, 万一角色未创建成功, 补充创建
        if (gameUserRole == null) {
            //未新建成功, 直接结束
            if (!this.gameRoleCreate(param, userData)) {
                return false;
            }
        } else {
            //角色信息更新
            this.gameRoleUpdate(param, gameUserRole, userData);
        }
        //进入游戏, 插入用户登录记录
        if (Objects.equals(dataType, DataTypeEnum.TYPE_ENTER_GAME.getDateType())) {
            userLoginLogService.createRoleLoginLog(userData, param, LoginTypeEnum.LOGIN_IN);
        }
        //退出游戏, 插入用户退出记录
        if (Objects.equals(dataType, DataTypeEnum.TYPE_EXIT_GAME.getDateType())) {
            userLoginLogService.createRoleLoginLog(userData, param, LoginTypeEnum.LOGIN_OUT);
        }
        return Boolean.TRUE;
    }

    private boolean gameRoleUpdate(GameUserRoleUpdateParam param, GameUserRole gameUserRole, UserData userData) {
        //更新频率限制, 20秒更新一次, 避免游戏实时战力高频上报
        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_LEVEL_UP + userData.getGameId()
                + "_" + param.getRoleId(), 0L, 20L, TimeUnit.SECONDS)) {
            return Boolean.TRUE;
        }
        //判断是否等级变更
        boolean updateRoleLevel = param.getRoleLevel() > gameUserRole.getRoleLevel();
        //角色vip等级
        if (param.getRoleVipLevel() != null) {
            gameUserRole.setRoleVipLevel(param.getRoleVipLevel());
        }
        //角色战力和帮派信息
        if (param.getRolePower() != null && param.getRolePower() > 0L) {
            gameUserRole.setRolePower(param.getRolePower());
        }
        //角色帮派/国家信息更新
        if (param.getExtra() != null && Strings.isNotBlank(JsonUtil.toString(param.getExtra()))) {
            gameUserRole.setExtra(JsonUtil.toString(param.getExtra()));
        }
        //其他信息更新
        gameUserRole.setRoleName(param.getRoleName());
        gameUserRole.setRoleLevel(param.getRoleLevel());
        gameUserRole.setServerName(param.getServerName());
        gameUserRole.setUpdateTime(LocalDateTime.now());
        boolean result = super.updateById(gameUserRole);
        //等级变更
        if (updateRoleLevel) {
            //用户创角回传
            callBackService.roleCallBack(gameUserRole);
            //玩家消息推送
            pushMsgService.pushMsgByLevelUpdate(param, userData);
        }
        //角色更新数据埋点发送到卡夫卡
        kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ROLE_UPDATE, JsonUtil.toString(gameUserRole));
        return result;
    }

    private boolean gameRoleCreate(GameUserRoleUpdateParam param, UserData userData) {
        //角色在游戏中已经存在, 不可创建
        if (this.count(new LambdaQueryWrapper<GameUserRole>()
                .eq(GameUserRole::getGameId, userData.getGameId())
                .eq(GameUserRole::getRoleId, param.getRoleId())
        ) > 0) {
            log.error("玩家收到别人角色上报, userId : {}, param : {}", userData.getUserId(), JsonUtil.toString(param));
            return false;
        }
        //查询玩家信息
        User user = userService.getOne(new LambdaQueryWrapper<User>()
                .eq(User::getId, userData.getUserId())
                .eq(User::getGameId, userData.getGameId()));
        GameUser gameUser = gameUserService.getOne(new LambdaQueryWrapper<GameUser>()
                .eq(GameUser::getGameId, userData.getGameId())
                .eq(GameUser::getUserId, userData.getUserId()));
        //参数不匹配
        if (user == null || gameUser == null) {
            log.error("角色上报玩家信息为空, userData : {}", JsonUtil.toString(userData));
            return false;
        }
        //上锁
        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_CREATE_LOCK + userData.getGameId()
                + "_" + param.getRoleId(), 0L, 3L, TimeUnit.MINUTES)) {
            return false;
        }
        //创建角色
        GameUserRole userRole = this.transform(param, userData, gameUser, user);
        super.save(userRole);
        //更新玩家创角数
        gameUserService.update(new LambdaUpdateWrapper<GameUser>()
                .setSql("role_count=role_count+" + 1)
                .set(GameUser::getUpdateTime, LocalDateTime.now())
                .eq(GameUser::getId, gameUser.getId()));
        //更新用户创角数
        userService.update(new LambdaUpdateWrapper<User>()
                .setSql("role_count=role_count+" + 1)
                .set(User::getUpdateTime, LocalDateTime.now())
                .eq(User::getId, user.getId()));
        //用户创角回传
        callBackService.roleCallBack(userRole);
        //用户创角埋点数据发送到卡夫卡
        kafkaService.eventTrack(KafkaEventTrackEnum.KAFKA_EVENT_TRACK_ROLE_CREATE, JsonUtil.toString(userRole));
        //创建角色通知监听服务
        this.callListenIn(param, userData);
        //角色操作记录添加
        roleOperateService.systemRoleOperate(userRole);
        //返回成功
        return true;
    }

    private GameUserRole transform(GameUserRoleUpdateParam param, UserData userData, GameUser gameUser, User user) {
        return GameUserRole.builder()
                .userId(userData.getUserId())
                .gameUserId(gameUser.getId())
                .gameId(userData.getGameId())
                .serverId(param.getServerId())
                .serverName(param.getServerName())
                .roleId(param.getRoleId())
                .roleName(param.getRoleName())
                .roleLevel(param.getRoleLevel())
                .roleVipLevel(param.getRoleVipLevel())
                .rolePower(param.getRolePower())
                .os(userData.getDeviceSystem())
                .regTime(user.getCreateTime())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .lastLoginTime(LocalDateTime.now())
                .extra(param.getExtra() == null || Strings.isBlank(JsonUtil.toString(param.getExtra())) ? null : JsonUtil.toString(param.getExtra()))
                .build();
    }

    @Override
    public void userGuideGameRoleCheck(User user, User relationUser) {
        //查询H5游戏角色列表
        List<GameUserRole> relationUserRoleList = super.list(new LambdaQueryWrapper<GameUserRole>()
                .eq(GameUserRole::getUserId, relationUser.getId())
                .eq(GameUserRole::getGameId, relationUser.getGameId()));
        //查询小游戏角色列表
        List<GameUserRole> userRoleList = super.list(new LambdaQueryWrapper<GameUserRole>()
                .eq(GameUserRole::getUserId, user.getId())
                .eq(GameUserRole::getGameId, user.getGameId()));
        //角色数量一致, 结束
        if (userRoleList.size() == relationUserRoleList.size()) {
            return;
        }
        //查询游戏玩家信息
        GameUser gameUser = gameUserService.getOne(new LambdaQueryWrapper<GameUser>()
                .eq(GameUser::getUserId, user.getId())
                .eq(GameUser::getGameId, user.getGameId()));
        if (gameUser == null) {
            return;
        }
        //循环
        List<GameUserRole> gameUserRoleList = new ArrayList<>();
        relationUserRoleList.forEach(gameUserRole -> {
            String roleId = gameUserRole.getRoleId();
            GameUserRole userRole = userRoleList.stream()
                    .filter(role -> Objects.equals(role.getRoleId(), roleId))
                    .findFirst().orElse(null);
            //缺少角色, 说明转到H5之后又重新在小程序登录创建了角色
            if (userRole == null) {
                gameUserRoleList.add(this.transform(user, gameUserRole, gameUser));
            }
        });
        if (CollectionUtils.isNotEmpty(gameUserRoleList)) {
            super.saveBatch(gameUserRoleList);
        }
    }

    private GameUserRole transform(User user, GameUserRole gameUserRole, GameUser gameUser) {
        return GameUserRole.builder()
                .userId(user.getId())
                .gameUserId(gameUser.getId())
                .gameId(user.getGameId())
                .serverId(gameUserRole.getServerId())
                .serverName(gameUserRole.getServerName())
                .roleId(gameUserRole.getRoleId())
                .roleName(gameUserRole.getRoleName())
                .roleLevel(gameUserRole.getRoleLevel())
                .roleVipLevel(gameUserRole.getRoleVipLevel())
                .rolePower(gameUserRole.getRolePower())
                .os(gameUserRole.getOs())
                .regTime(gameUserRole.getCreateTime())
                .createTime(gameUserRole.getCreateTime())
                .updateTime(gameUserRole.getUpdateTime())
                .lastLoginTime(gameUserRole.getLastLoginTime())
                .build();
    }

    private void callListenIn(GameUserRoleUpdateParam param, UserData userData) {
        Map<String, String> map = new HashMap<>(2);
        map.put("json", JsonUtil.toString(param));
        map.put("userData", JsonUtil.toString(userData));
        //创角通知监听服务
        try {
            restTemplate.postForObject("http://47.99.157.216:9000/game/roleReport", map, Object.class);
        } catch (Exception ignored) {
        }
    }

    @Override
    public boolean gameRoleActiveCall(UserData userData, GameRoleActiveCallParam param) {
        //测试不执行
        if (this.serverUrl.contains("test")) {
            return Boolean.TRUE;
        }
        //token临期失效判断
        try {
            userTokenService.userTokenUpdateCheck(userData);
        } catch (Exception ignored) {
        }
        //活跃信息发送到卡夫卡
        kafkaService.roleActiveTrack(userData, param);
        return Boolean.TRUE;
    }
}
