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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zanxiang.corp.base.CorpServer;
import com.zanxiang.corp.base.pojo.dto.CorpExternalUserDTO;
import com.zanxiang.corp.base.rpc.ICorpExternalUserServiceRpc;
import com.zanxiang.game.module.base.pojo.enums.GameCategoryEnum;
import com.zanxiang.game.module.base.util.DateUtils;
import com.zanxiang.game.module.manage.pojo.dto.AgentDTO;
import com.zanxiang.game.module.manage.pojo.dto.CpDTO;
import com.zanxiang.game.module.manage.pojo.dto.GameDTO;
import com.zanxiang.game.module.manage.pojo.dto.UserDTO;
import com.zanxiang.game.module.manage.pojo.params.UserListParam;
import com.zanxiang.game.module.manage.pojo.params.UserUpdateParam;
import com.zanxiang.game.module.manage.pojo.vo.UserCardVO;
import com.zanxiang.game.module.manage.pojo.vo.UserListVO;
import com.zanxiang.game.module.manage.pojo.vo.UserVO;
import com.zanxiang.game.module.manage.pojo.vo.UserWeChatVO;
import com.zanxiang.game.module.manage.service.*;
import com.zanxiang.game.module.mybatis.entity.Agent;
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.UserMapper;
import com.zanxiang.module.util.bean.BeanUtil;
import com.zanxiang.module.util.encryption.Md5Util;
import com.zanxiang.module.util.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
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 reactor.util.function.Tuple2;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author : lingfeng
 * @time : 2022-06-07
 * @description : 用户玩家
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @DubboReference(providedBy = CorpServer.SERVER_DUBBO_NAME)
    private ICorpExternalUserServiceRpc corpExternalUserServiceRpc;

    @Autowired
    private IGameService gameService;

    @Autowired
    private ICpService cpService;

    @Autowired
    private IUserCardService userCardService;

    @Autowired
    private IAgentService agentService;

    @Autowired
    private IGameUserRoleService gameUserRoleService;

    @Autowired
    private IGameUserService gameUserService;

    @Autowired
    private IGameAuthService gameAuthService;

    @Autowired
    private IUserAgentLogService userAgentLogService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean appletToH5(Long userId, String mobile, Integer type) {
        //用户信息
        User user = super.getById(userId);
        if (user == null) {
            throw new BaseException("参数错误, 用户信息不存在");
        }
        GameDTO gameDTO;
        //查询H5游戏
        if (type == 1) {
            gameDTO = gameService.getById(gameService.getById(user.getGameId()).getH5GameId());
        } else if (type == 2) {
            //查询安卓游戏
            gameDTO = gameService.getById(gameService.getById(user.getGameId()).getAndroidGameId());
        } else if (type == 3) {
            //查询ios游戏
            gameDTO = gameService.getById(gameService.getById(user.getGameId()).getIosGameId());
        } else {
            throw new BaseException("参数错误, 导量类型不存在");
        }
        //判断关联游戏是否存在
        if (gameDTO == null) {
            throw new BaseException("参数错误, 关联导量游戏信息不存在");
        }
        //判断该玩家是否已经导过该游戏
        if (super.count(new LambdaQueryWrapper<User>()
                .eq(User::getGameId, gameDTO.getId())
                .eq(User::getRelationUserId, userId)
        ) > 0) {
            throw new BaseException("玩家已经导到该游戏端, 请不要重复操作");
        }
        //判断手机号是否被该游戏其他用户绑定
        if (super.count(new LambdaQueryWrapper<User>()
                .eq(User::getGameId, gameDTO.getId())
                .eq(User::getMobile, mobile)
        ) > 0) {
            throw new BaseException("手机号已被游戏其他玩家绑定");
        }
        //复制用户信息
        User h5User = BeanUtil.copy(user, User.class);
        h5User.setId(null);
        h5User.setGameId(gameDTO.getId());
        h5User.setMobile(mobile);
        h5User.setRelationUserId(user.getId());
        h5User.setRelationGameId(user.getGameId());
        h5User.setRelationCreateTime(LocalDateTime.now());
        h5User.setImportUser(1);
        //充值统计数据归零设置
        h5User.setSessionKey(null);
        h5User.setRechargeCount(0);
        h5User.setRechargeMoney(BigDecimal.ZERO);
        h5User.setLastRechargeTime(null);
        super.save(h5User);
        //复制玩家信息
        GameUser gameUser = gameUserService.getOne(new LambdaQueryWrapper<GameUser>()
                .eq(GameUser::getUserId, user.getId())
                .eq(GameUser::getGameId, user.getGameId()));
        if (gameUser == null) {
            throw new BaseException("参数错误, 玩家游戏信息不存在");
        }
        GameUser h5GameUser = GameUser.builder()
                .userId(h5User.getId())
                .gameId(h5User.getGameId())
                .nickname(gameUser.getNickname())
                .regTime(gameUser.getRegTime())
                .createTime(gameUser.getCreateTime())
                .updateTime(gameUser.getUpdateTime())
                .build();
        gameUserService.save(h5GameUser);
        //复制角色
        List<GameUserRole> gameUserRoleList = gameUserRoleService.list(new LambdaQueryWrapper<GameUserRole>()
                .eq(GameUserRole::getUserId, user.getId())
                .eq(GameUserRole::getGameId, user.getGameId()));
        if (CollectionUtils.isEmpty(gameUserRoleList)) {
            throw new BaseException("参数错误, 用户不存在角色信息");
        }
        List<GameUserRole> h5GameUserRoleList = gameUserRoleList.stream().map(gameUserRole -> GameUserRole.builder()
                .userId(h5User.getId())
                .gameUserId(h5GameUser.getId())
                .gameId(h5User.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.getRegTime())
                .createTime(gameUserRole.getCreateTime())
                .updateTime(gameUserRole.getUpdateTime())
                .lastLoginTime(gameUserRole.getLastLoginTime())
                .build()
        ).collect(Collectors.toList());
        gameUserRoleService.saveBatch(h5GameUserRoleList);
        //用户更新
        super.update(new LambdaUpdateWrapper<User>()
                .set(User::getRelationUserId, h5User.getId())
                .set(User::getRelationCreateTime, LocalDateTime.now())
                .eq(User::getId, userId));
        //添加导量用户的渠道变更记录
        return userAgentLogService.regAgentLog(h5User);
    }

    @Override
    public UserWeChatVO getUserWeChat(Long userId) {
        User user = super.getById(userId);
        if (user == null) {
            throw new BaseException("参数错误, 用户信息不存在");
        }
        Map<String, String> channelTransform = agentService.channelTransform(user.getChannel());
        if (channelTransform.containsKey("params")) {
            String[] params = channelTransform.get("params").split(":");
            CorpExternalUserDTO corpExternalUser = corpExternalUserServiceRpc.getCorpExternalUser(params[0], params[1]).getData();
            if (corpExternalUser != null) {
                return BeanUtil.copy(corpExternalUser, UserWeChatVO.class);
            }
        }
        throw new BaseException("未查询到用户微信信息");
    }

    @Override
    public IPage<UserListVO> list(UserListParam param) {
        //游戏获取
        Tuple2<String, List<Long>> gameTuple = gameAuthService.getUserGameList(param.getPitcherId());
        if (CollectionUtils.isEmpty(gameTuple.getT2())) {
            return new Page<>();
        }
        //游戏条件处理
        Map<Long, GameDTO> gameMap = gameService.gameCondition(gameTuple.getT2(), param.getCpId(), param.getGameId(), param.getGameCategoryId());
        if (CollectionUtils.isEmpty(gameMap)) {
            return new Page<>();
        }
        //渠道获取
        Tuple2<List<Long>, List<AgentDTO>> tuple2 = agentService.getUserAgent(param.getAccountId(), param.getPitcherId(), param.getChannelId());
        List<Long> agentIdList = tuple2.getT1();
        List<AgentDTO> agentDTOList = tuple2.getT2();
        if (CollectionUtils.isEmpty(agentIdList)) {
            return new Page<>();
        }
        Map<Long, CpDTO> cpMap = cpService.cpMap();
        //执行查询
        return page(param.toPage(), new QueryWrapper<User>().lambda()
                .in(User::getGameId, gameMap.keySet())
                .eq(param.getUserId() != null, User::getId, param.getUserId())
                .like(Strings.isNotBlank(param.getUserName()), User::getUsername, param.getUserName())
                .like(Strings.isNotBlank(param.getNickname()), User::getNickname, param.getNickname())
                .eq(Strings.isNotBlank(param.getMobile()), User::getMobile, param.getMobile())
                .eq(Strings.isNotBlank(param.getRegIp()), User::getIp, param.getRegIp())
                .eq(Objects.equals(param.getIsAuth(), Boolean.FALSE), User::getAuthentication, 0)
                .ne(Objects.equals(param.getIsAuth(), Boolean.TRUE), User::getAuthentication, 0)
                .isNotNull(Objects.equals(param.getIsBindMobile(), Boolean.TRUE), User::getMobile)
                .isNull(Objects.equals(param.getIsBindMobile(), Boolean.FALSE), User::getMobile)
                .ge(param.getBeginDate() != null, User::getCreateTime, param.getBeginDate() == null ? null : LocalDateTime.of(param.getBeginDate(), LocalTime.MIN))
                .le(param.getEndDate() != null, User::getCreateTime, param.getEndDate() == null ? null : LocalDateTime.of(param.getEndDate(), LocalTime.MAX))
                .ge(param.getRechargeBeginDate() != null, User::getLastRechargeTime, param.getRechargeBeginDate() == null ? null : LocalDateTime.of(param.getRechargeBeginDate(), LocalTime.MIN))
                .le(param.getRechargeEndDate() != null, User::getLastRechargeTime, param.getRechargeEndDate() == null ? null : LocalDateTime.of(param.getRechargeEndDate(), LocalTime.MAX))
                .gt(Objects.equals(param.getIsRecharge(), Boolean.TRUE), User::getRechargeCount, 0)
                .eq(Objects.equals(param.getIsRecharge(), Boolean.FALSE), User::getRechargeCount, 0)
                .eq(param.getStatus() != null, User::getStatus, param.getStatus())
                .in(CollectionUtils.isNotEmpty(agentIdList), User::getAgentId, agentIdList)
                .apply(param.getRegPayIntervalTimeMin() != null, "if(last_recharge_time is not null, TIMESTAMPDIFF(minute, create_time, last_recharge_time), null) >= {0}", param.getRegPayIntervalTimeMin())
                .apply(param.getRegPayIntervalTimeMax() != null, "if(last_recharge_time is not null, TIMESTAMPDIFF(minute, create_time, last_recharge_time), null) <= {0}", param.getRegPayIntervalTimeMax())
                .gt(Objects.equals(param.getCreateRole(), Boolean.TRUE), User::getRoleCount, 0)
                .le(Objects.equals(param.getCreateRole(), Boolean.FALSE), User::getRoleCount, 0)
                .ge(param.getRoleCountMin() != null, User::getRoleCount, param.getRoleCountMin())
                .le(param.getRoleCountMax() != null, User::getRoleCount, param.getRoleCountMax())
                .orderByDesc(User::getCreateTime)
        ).convert(u -> this.toVo(u, gameMap, cpMap, agentDTOList));
    }

    private UserListVO toVo(User user, Map<Long, GameDTO> gameMap, Map<Long, CpDTO> cpMap, List<AgentDTO> agentDTOList) {
        UserListVO userListVO = BeanUtil.copy(user, UserListVO.class);
        if (Objects.isNull(userListVO)) {
            return null;
        }
        //手机号隐藏
        userListVO.setMobile(user.getShowPhoneNum());
        userListVO.setRegIp(user.getIp());
        //渠道信息
        AgentDTO agentDTO = agentDTOList.stream().filter(dto -> Objects.equals(dto.getId(), userListVO.getAgentId()))
                .findFirst().orElse(null);
        if (agentDTO != null) {
            userListVO.setAgentName(agentDTO.getAgentName());
            userListVO.setPitcherId(agentDTO.getCreateBy());
            userListVO.setPitcherName(agentDTO.getCreateByName());
            userListVO.setAccountId(agentDTO.getAccountId());
            userListVO.setAccountType(agentDTO.getAccountType());
        }
        if (Objects.equals(Agent.DEFAULT_AGENT, userListVO.getAgentId())) {
            userListVO.setAgentName(Agent.DEFAULT_AGENT_NAME);
        }
        //游戏信息
        GameDTO gameDTO = CollectionUtils.isNotEmpty(gameMap) ? gameMap.get(userListVO.getGameId()) : gameService.getById(userListVO.getGameId());
        if (gameDTO != null) {
            userListVO.setGameName(gameDTO.getName());
            userListVO.setGameCategoryId(gameDTO.getCategory());
            userListVO.setGameCategoryName(GameCategoryEnum.getNameByCategory(gameDTO.getCategory()));
            userListVO.setCpId(gameDTO.getCpId());
            userListVO.setCpName(cpMap.get(gameDTO.getCpId()) == null ? null : cpMap.get(gameDTO.getCpId()).getCpName());
        }
        //最近角色
        GameUserRole gameUserRole = gameUserRoleService.getLastGameUserRoleName(user.getId(), user.getGameId());
        if (gameUserRole != null) {
            userListVO.setLastGameRoleName(gameUserRole.getRoleName());
            userListVO.setUpdateTime(gameUserRole.getLastLoginTime());
        }
        //注册充值时间差
        userListVO.setRegPayTimeDiff(DateUtils.getRegPayTimeDiff(userListVO.getCreateTime(), userListVO.getLastRechargeTime()));
        //设置关联游戏名称
        if (userListVO.getRelationUserId() != null) {
            User relationUser = super.getById(userListVO.getRelationUserId());
            GameDTO relationGame = gameService.getById(relationUser.getGameId());
            userListVO.setRelationGameId(relationGame.getId());
            userListVO.setRelationGameName(relationGame.getName());
        }
        //返回
        return userListVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean userUpdate(UserUpdateParam param) {
        if (Strings.isNotBlank(param.getMobile()) && !param.getMobile().contains("*")) {
            User user = super.getById(param.getUserId());
            //判断手机号是否被该游戏其他用户绑定
            if (super.count(new LambdaQueryWrapper<User>()
                    .eq(User::getGameId, user.getGameId())
                    .eq(User::getMobile, param.getMobile())
            ) > 0) {
                throw new BaseException("手机号已被同游戏其他玩家绑定, 禁止修改");
            }
        }
        //用户信息更新
        if (Strings.isNotBlank(param.getMobile()) || Strings.isNotBlank(param.getAliPay()) || Strings.isNotBlank(param.getPassword())) {
            super.update(new LambdaUpdateWrapper<User>()
                    .eq(User::getId, param.getUserId())
                    .eq(User::getUsername, param.getUsername())
                    .set(Strings.isNotBlank(param.getMobile()) && !param.getMobile().contains("*"), User::getMobile, param.getMobile())
                    .set(Strings.isNotBlank(param.getAliPay()), User::getAliPay, param.getAliPay())
                    .set(Strings.isNotBlank(param.getPassword()), User::getPassword, this.cmfPassword(param.getPassword()))
                    .set(User::getUpdateTime, LocalDateTime.now()));
        }
        return Boolean.TRUE;
    }

    private String cmfPassword(String password) {
        String passwordSalt = password + "ZX_PASSWORD_SALT";
        return "###" + Md5Util.encrypt32(Md5Util.encrypt32(passwordSalt));
    }

    @Override
    public UserVO getUserInfo(Long userId) {
        //查询用户信息
        User user = super.getById(userId);
        UserVO userVO = BeanUtil.copy(user, UserVO.class);
        if (userVO == null) {
            throw new BaseException("用户信息不存在!");
        }
        //查询用户拓展信息
        UserCardVO userCardVO = userCardService.getByUserId(userId);
        //拓展信息补充
        userVO.setRealName(userCardVO == null ? null : userCardVO.getCardName());
        userVO.setBirthday(userCardVO == null ? null : userCardVO.getBirthday());
        userVO.setSex(userCardVO == null ? null : userCardVO.getSex());
        userVO.setIdCard(userCardVO == null ? null : userCardVO.getCardId());
        userVO.setRegMobile(user.getShowPhoneNum());
        userVO.setMobile(user.getShowPhoneNum());
        userVO.setRegEmail(user.getEmail());
        userVO.setRegIp(user.getIp());
        userVO.setDeviceId(user.getMac());
        //注册游戏
        GameDTO gameDTO = gameService.getById(user.getGameId());
        if (gameDTO != null) {
            userVO.setRegGame(gameDTO.getName());
            userVO.setCategoryName(GameCategoryEnum.getNameByCategory(gameDTO.getCategory()));
        }
        //渠道
        Agent agent = agentService.getById(user.getAgentId());
        if (agent != null) {
            userVO.setChannelName(agent.getAgentName());
            userVO.setRegFrom(agent.getAccountType());
        }
        return userVO;
    }

    @Override
    public Map<Long, UserDTO> userCondition(Long userId, List<Long> agentIdList, String userName, String nickname,
                                            String regIp, LocalDate regTimeBeginDate, LocalDate regTimeEndDate) {
        //用户信息条件处理
        if (userId == null && CollectionUtils.isEmpty(agentIdList) && Strings.isBlank(userName)
                && Strings.isBlank(nickname) && Strings.isBlank(regIp)) {
            return null;
        }
        //查询
        List<User> userList = super.list(new LambdaQueryWrapper<User>()
                .eq(userId != null, User::getId, userId)
                .in(CollectionUtils.isNotEmpty(agentIdList), User::getAgentId, agentIdList)
                .eq(Strings.isNotBlank(regIp), User::getIp, regIp)
                .like(Strings.isNotBlank(userName), User::getUsername, userName)
                .like(Strings.isNotBlank(nickname), User::getNickname, nickname)
                .ge(regTimeBeginDate != null, User::getCreateTime, regTimeBeginDate == null ? null : LocalDateTime.of(regTimeBeginDate, LocalTime.MIN))
                .le(regTimeEndDate != null, User::getCreateTime, regTimeEndDate == null ? null : LocalDateTime.of(regTimeEndDate, LocalTime.MAX))
                .select(User::getId, User::getUsername, User::getNickname, User::getIp, User::getCreateTime, User::getAgentId));
        if (CollectionUtils.isEmpty(userList)) {
            return Collections.emptyMap();
        }
        return userList.stream()
                .map(user -> BeanUtil.copy(user, UserDTO.class))
                .collect(Collectors.toMap(UserDTO::getId, Function.identity()));
    }

    @Override
    public Map<Long, UserDTO> getByUserIds(List<Long> userIdList) {
        if (CollectionUtils.isEmpty(userIdList)) {
            return Collections.emptyMap();
        }
        //查询
        List<User> userList = super.listByIds(userIdList);
        if (CollectionUtils.isEmpty(userList)) {
            return Collections.emptyMap();
        }
        return userList.stream().map(user -> BeanUtil.copy(user, UserDTO.class))
                .collect(Collectors.toMap(UserDTO::getId, Function.identity()));
    }

    @Override
    public UserDTO getById(Long userId) {
        return BeanUtil.copy(super.getById(userId), UserDTO.class);
    }

}
