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.GameUser;
import com.zanxiang.game.module.mybatis.entity.GameUserRole;
import com.zanxiang.game.module.mybatis.entity.User;
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.LoginTypeEnum;
import com.zanxiang.game.module.sdk.pojo.param.GameRoleActiveCallParam;
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.IGameUserRoleService;
import com.zanxiang.game.module.sdk.service.IGameUserService;
import com.zanxiang.game.module.sdk.service.IUserLoginLogService;
import com.zanxiang.game.module.sdk.service.IUserService;
import com.zanxiang.module.redis.service.IDistributedLockComponent;
import com.zanxiang.module.util.DateUtil;
import com.zanxiang.module.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
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 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 {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IGameUserService gameUserService;

    @Autowired
    private IUserService userService;

    @Autowired
    private IUserLoginLogService userLoginLogService;

    @Autowired
    private IDistributedLockComponent distributedLockComponent;

    @Value("${spring.kafka.game-sdk.gameRoleActiveTopic}")
    private String gameRoleActiveTopic;

    @Autowired
    @Qualifier("gameSdkKafkaProducer")
    private KafkaProducer<String, String> kafkaProducer;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateUserGameRole(GameUserRoleUpdateParam param, UserData userData) {
        log.error("上报用户信息, param : {}", JsonUtil.toString(param));
        //上报类型
        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())) {
            //新建游戏角色
            this.createRoleUpdate(param, userData);
            //插入用户登录记录
            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(), LoginTypeEnum.LOGIN_IN.getLoginType());
        }
        //判断角色是否存在
        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) {
            //新建游戏角色
            this.createRoleUpdate(param, userData);
        }
        //进入游戏
        if (Objects.equals(dataType, DataTypeEnum.TYPE_ENTER_GAME.getDateType())) {
            //插入用户登录记录
            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(), LoginTypeEnum.LOGIN_IN.getLoginType());
        }
        //等级提升更新
        if (Objects.equals(dataType, DataTypeEnum.TYPE_LEVEL_UP.getDateType())) {
            return super.update(new LambdaUpdateWrapper<GameUserRole>()
                    .set(GameUserRole::getRoleName, param.getRoleName())
                    .set(GameUserRole::getRoleLevel, param.getRoleLevel())
                    .set(GameUserRole::getServerId, param.getServerId())
                    .set(GameUserRole::getServerName, param.getServerName())
                    .set(param.getRoleVipLevel() != null, GameUserRole::getRoleVipLevel, param.getRoleVipLevel())
                    .set(param.getRolePower() != null, GameUserRole::getRolePower, param.getRolePower())
                    .set(GameUserRole::getUpdateTime, param.getRoleGradeUpdateTime() == null || param.getRoleGradeUpdateTime() <= 0 ? LocalDateTime.now() : DateUtil.secondToLocalDateTime(param.getRoleGradeUpdateTime()))
                    .eq(GameUserRole::getUserId, userData.getUserId())
                    .eq(GameUserRole::getGameId, userData.getGameId())
                    .eq(GameUserRole::getRoleId, param.getRoleId()));
        }
        //退出游戏
        if (Objects.equals(dataType, DataTypeEnum.TYPE_EXIT_GAME.getDateType())) {
            //插入用户退出记录
            return userLoginLogService.createRoleLoginLog(userData, param.getRoleId(), param.getRoleName(), LoginTypeEnum.LOGIN_OUT.getLoginType());
        }
        return Boolean.FALSE;
    }

    private void createRoleUpdate(GameUserRoleUpdateParam param, UserData userData) {
        //上锁
        if (!distributedLockComponent.doLock(RedisKeyConstant.ROLE_UPDATE_KEY + "_" + userData.getUserId(), 0L, 1L, TimeUnit.MINUTES)) {
            return;
        }
        //查询玩家信息
        GameUser gameUser = gameUserService.getOne(new LambdaQueryWrapper<GameUser>().eq(GameUser::getGameId, userData.getGameId())
                .eq(GameUser::getUserId, userData.getUserId()));
        //查询玩家角色信息
        GameUserRole userRole = this.getOne(new LambdaQueryWrapper<GameUserRole>()
                .eq(GameUserRole::getGameId, userData.getGameId())
                .eq(GameUserRole::getRoleId, param.getRoleId()));
        if (userRole != null) {
            //释放锁
            distributedLockComponent.unlock(RedisKeyConstant.ROLE_UPDATE_KEY + "_" + userData.getUserId());
            return;
        }
        User user = userService.getById(userData.getUserId());
        userRole = 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 == null ? null : user.getCreateTime())
                .createTime(param.getRoleGradeUpdateTime() == null || param.getRoleGradeUpdateTime() <= 0 ? LocalDateTime.now() : DateUtil.secondToLocalDateTime(param.getRoleGradeUpdateTime()))
                .updateTime(LocalDateTime.now())
                .lastLoginTime(LocalDateTime.now())
                .build();
        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, gameUser.getUserId()));
        //释放锁
        distributedLockComponent.unlock(RedisKeyConstant.ROLE_UPDATE_KEY + "_" + userData.getUserId());
    }

    @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();
    }

    @Override
    public 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) {
        log.error("接收到前端用户角色活跃上报, userId : {}, gameId : {}, serverId : {}, roleId : {}, roleLevel : {}",
                userData.getUserId(), userData.getGameId(), param.getServerId(), param.getRoleId(), param.getRoleLevel());
        Map<String, Object> activeParamMap = new HashMap<>(6);
        activeParamMap.put("userId", userData.getUserId());
        activeParamMap.put("gameId", userData.getGameId());
        activeParamMap.put("serverId", param.getServerId());
        activeParamMap.put("roleId", param.getRoleId());
        activeParamMap.put("roleLevel", param.getRoleLevel());
        activeParamMap.put("activeTime", System.currentTimeMillis());
        try {
            kafkaProducer.send(new ProducerRecord<>(gameRoleActiveTopic, userData.getUserId().toString(), JsonUtil.toString(activeParamMap)));
        } catch (Exception e) {
            log.error("用户角色活跃信息发送到 Kafka 异常!, activeParamMap : {}, e : {}", JsonUtil.toString(activeParamMap), e.getMessage());
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }
}
