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.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.erp.security.util.SecurityUtil;
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.*;
import com.zanxiang.game.module.manage.pojo.params.GameUserRoleListParam;
import com.zanxiang.game.module.manage.pojo.vo.GameUserRoleExcelVO;
import com.zanxiang.game.module.manage.pojo.vo.GameUserRoleListVO;
import com.zanxiang.game.module.manage.pojo.vo.GameUserRoleVO;
import com.zanxiang.game.module.manage.service.*;
import com.zanxiang.game.module.mybatis.entity.Agent;
import com.zanxiang.game.module.mybatis.entity.GameServer;
import com.zanxiang.game.module.mybatis.entity.GameUserRole;
import com.zanxiang.game.module.mybatis.mapper.GameUserRoleMapper;
import com.zanxiang.module.util.bean.BeanUtil;
import com.zanxiang.module.util.excel.ExcelUtil;
import com.zanxiang.module.util.exception.BaseException;
import com.zanxiang.module.web.util.WebExcelUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.util.function.Tuple2;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author : lingfeng
 * @time : 2022-07-01
 * @description : 玩家角色
 */
@Slf4j
@Service
public class GameUserRoleServiceImpl extends ServiceImpl<GameUserRoleMapper, GameUserRole> implements IGameUserRoleService {

    @Autowired
    private IUserService userService;

    @Autowired
    private IGameService gameService;

    @Autowired
    private ICpService cpService;

    @Autowired
    private IAgentService agentService;

    @Autowired
    private IGameServerService gameServerService;

    @Autowired
    private IGameAuthService gameAuthService;

    @Override
    public GameUserRole getLastGameUserRoleName(Long userId, Long gameId) {
        return super.getOne(new LambdaQueryWrapper<GameUserRole>()
                .eq(GameUserRole::getUserId, userId)
                .eq(GameUserRole::getGameId, gameId)
                .orderByDesc(GameUserRole::getUpdateTime)
                .last("limit 1"));
    }

    @Override
    public GameUserRoleDTO getByRoleId(Long userId, Long gameId, String roleId) {
        GameUserRole gameUserRole = super.getOne(new LambdaQueryWrapper<GameUserRole>()
                .eq(GameUserRole::getUserId, userId)
                .eq(GameUserRole::getGameId, gameId)
                .eq(GameUserRole::getRoleId, roleId));
        return BeanUtil.copy(gameUserRole, GameUserRoleDTO.class);
    }

    @Override
    public List<GameUserRoleVO> roleList(Long userId) {
        List<GameUserRole> gameUserRoleList = super.list(new LambdaQueryWrapper<GameUserRole>().eq(GameUserRole::getUserId, userId));
        if (CollectionUtils.isEmpty(gameUserRoleList)) {
            return Collections.emptyList();
        }
        //玩家信息
        UserDTO userDTO = userService.getById(userId);
        //游戏信息
        GameDTO gameDTO = gameService.getById(userDTO.getGameId());
        //渠道信息
        String agentName;
        if (Objects.equals(userDTO.getAgentId(), Agent.DEFAULT_AGENT)) {
            agentName = Agent.DEFAULT_AGENT_NAME;
        } else {
            Agent agent = agentService.getById(userDTO.getAgentId());
            agentName = agent.getAgentName();
        }
        return gameUserRoleList.stream().map(role -> {
            GameUserRoleVO gameUserRoleVO = BeanUtil.copy(role, GameUserRoleVO.class);
            //设置游戏名称
            gameUserRoleVO.setGameName(gameDTO.getName());
            gameUserRoleVO.setGameCategoryName(GameCategoryEnum.getNameByCategory(gameDTO.getCategory()));
            //设置渠道信息
            gameUserRoleVO.setAgentName(agentName);
            return gameUserRoleVO;
        }).collect(Collectors.toList());
    }

    @Override
    public IPage<GameUserRoleListVO> list(GameUserRoleListParam 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, UserDTO> userMap = userService.userCondition(param.getUserId(), agentIdList, param.getUserName(),
                param.getNickname(), param.getRegIp(), param.getRegTimeBeginDate(), param.getRegTimeEndDate());
        //根据条件, 匹配不到玩家
        if (userMap != null && userMap.isEmpty()) {
            return new Page<>();
        }
        //区服筛选
        List<String> serverIdList = gameServerService.listServerId(param.getGameId(), param.getServerName());
        //相关用户id
        Set<Long> userIdSet = userMap == null ? null : userMap.keySet();
        Map<Long, CpDTO> cpMap = cpService.cpMap();
        Map<Long, AgentDTO> agentMap = agentDTOList.stream().collect(Collectors.toMap(AgentDTO::getId, Function.identity()));
        //执行查询
        return page(param.toPage(), new QueryWrapper<GameUserRole>().lambda()
                .in(GameUserRole::getGameId, gameMap.keySet())
                .in(CollectionUtils.isNotEmpty(userIdSet), GameUserRole::getUserId, userIdSet)
                .in(CollectionUtils.isNotEmpty(serverIdList), GameUserRole::getServerId, serverIdList)
                .like(Strings.isNotBlank(param.getRoleName()), GameUserRole::getRoleName, param.getRoleName())
                .eq(Strings.isNotBlank(param.getOs()), GameUserRole::getOs, param.getOs())
                .gt(Objects.equals(param.getIsRecharge(), Boolean.TRUE), GameUserRole::getRechargeCount, 0)
                .eq(Objects.equals(param.getIsRecharge(), Boolean.FALSE), GameUserRole::getRechargeCount, 0)
                .eq(param.getVipLevel() != null && param.getVipLevel() <= 10, GameUserRole::getRoleVipLevel, param.getVipLevel())
                .gt(param.getVipLevel() != null && param.getVipLevel() > 10, GameUserRole::getRoleVipLevel, param.getVipLevel())
                .ge(param.getBeginDate() != null, GameUserRole::getCreateTime, param.getBeginDate() == null ? null : LocalDateTime.of(param.getBeginDate(), LocalTime.MIN))
                .le(param.getEndDate() != null, GameUserRole::getCreateTime, param.getEndDate() == null ? null : LocalDateTime.of(param.getEndDate(), LocalTime.MAX))
                .ge(param.getRechargeBeginDate() != null, GameUserRole::getLastRechargeTime, param.getRechargeBeginDate() == null ? null : LocalDateTime.of(param.getRechargeBeginDate(), LocalTime.MIN))
                .le(param.getRechargeEndDate() != null, GameUserRole::getLastRechargeTime, param.getRechargeEndDate() == null ? null : LocalDateTime.of(param.getRechargeEndDate(), LocalTime.MAX))
                .ge(param.getRoleLevelMin() != null, GameUserRole::getRoleLevel, param.getRoleLevelMin())
                .le(param.getRoleLevelMax() != null, GameUserRole::getRoleLevel, param.getRoleLevelMax())
                .apply(param.getRegPayIntervalTimeMin() != null, "if(last_recharge_time is not null, TIMESTAMPDIFF(minute, reg_time, last_recharge_time), null) >= {0}", param.getRegPayIntervalTimeMin())
                .apply(param.getRegPayIntervalTimeMax() != null, "if(last_recharge_time is not null, TIMESTAMPDIFF(minute, reg_time, last_recharge_time), null) <= {0}", param.getRegPayIntervalTimeMax())
                .orderByDesc(GameUserRole::getCreateTime)
        ).convert(u -> this.toVo(u, userMap, gameMap, cpMap, agentMap));
    }

    private GameUserRoleListVO toVo(GameUserRole gameUserRole, Map<Long, UserDTO> userMap, Map<Long, GameDTO> gameMap,
                                    Map<Long, CpDTO> cpMap, Map<Long, AgentDTO> agentMap) {
        GameUserRoleListVO gameUserRoleListVO = BeanUtil.copy(gameUserRole, GameUserRoleListVO.class);
        if (Objects.isNull(gameUserRoleListVO)) {
            return null;
        }
        UserDTO userDTO = CollectionUtils.isEmpty(userMap) ? null : userMap.get(gameUserRoleListVO.getUserId());
        if (userDTO == null) {
            userDTO = userService.getById(gameUserRoleListVO.getUserId());
        }
        if (userDTO != null) {
            gameUserRoleListVO.setUsername(userDTO.getUsername());
            gameUserRoleListVO.setNickname(userDTO.getNickname());
            gameUserRoleListVO.setRegIp(userDTO.getIp());
            gameUserRoleListVO.setRegTime(userDTO.getCreateTime());
            gameUserRoleListVO.setAgentId(userDTO.getAgentId());
            AgentDTO agentDTO = agentMap.get(userDTO.getAgentId());
            if (agentDTO != null) {
                gameUserRoleListVO.setAgentName(agentDTO.getAgentName());
                gameUserRoleListVO.setAccountId(agentDTO.getAccountId());
                gameUserRoleListVO.setPitcherId(agentDTO.getCreateBy());
                gameUserRoleListVO.setPitcherName(agentDTO.getCreateByName());
                gameUserRoleListVO.setAccountType(agentDTO.getAccountType());
            }
            if (Objects.equals(Agent.DEFAULT_AGENT, gameUserRoleListVO.getAgentId())) {
                gameUserRoleListVO.setAgentName(Agent.DEFAULT_AGENT_NAME);
            }
        }
        GameDTO gameDTO = CollectionUtils.isEmpty(gameMap) ? null : gameMap.get(gameUserRoleListVO.getGameId());
        if (gameDTO == null) {
            gameDTO = gameService.getById(gameUserRoleListVO.getGameId());
        }
        if (gameDTO != null) {
            //设置源服务器名称
            GameServer gameServer = gameServerService.getOne(new LambdaQueryWrapper<GameServer>()
                    .eq(GameServer::getGameId, gameDTO.getSuperGameId())
                    .eq(GameServer::getServerId, gameUserRole.getServerId()));
            if (gameServer != null) {
                gameUserRoleListVO.setSourceServerName(gameServer.getServerName());
            }
            gameUserRoleListVO.setGameName(gameDTO.getName());
            gameUserRoleListVO.setCpId(gameDTO.getCpId());
            gameUserRoleListVO.setCpName(cpMap.get(gameDTO.getCpId()) == null ? null : cpMap.get(gameDTO.getCpId()).getCpName());
            gameUserRoleListVO.setGameCategoryId(gameDTO.getCategory());
            gameUserRoleListVO.setGameCategoryName(GameCategoryEnum.getNameByCategory(gameDTO.getCategory()));
        }
        //注册充值时间差
        gameUserRoleListVO.setRegPayTimeDiff(DateUtils.getRegPayTimeDiff(gameUserRoleListVO.getRegTime(), gameUserRoleListVO.getLastRechargeTime()));
        return gameUserRoleListVO;
    }

    @Override
    public void getGameUserRoleExcel(GameUserRoleListParam param, HttpServletResponse response) {
        if (!SecurityUtil.isAdmin()) {
            throw new BaseException("没有下载权限");
        }
        //游戏获取
        Tuple2<String, List<Long>> gameTuple = gameAuthService.getUserGameList(param.getPitcherId());
        if (CollectionUtils.isEmpty(gameTuple.getT2())) {
            return;
        }
        //游戏条件处理
        Map<Long, GameDTO> gameMap = gameService.gameCondition(gameTuple.getT2(), param.getCpId(), param.getGameId(), param.getGameCategoryId());
        if (CollectionUtils.isEmpty(gameMap)) {
            return;
        }
        //渠道获取
        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;
        }
        //玩家条件处理
        Map<Long, UserDTO> userMap = userService.userCondition(param.getUserId(), agentIdList, param.getUserName(),
                param.getNickname(), param.getRegIp(), param.getRegTimeBeginDate(), param.getRegTimeEndDate());
        //根据条件, 匹配不到玩家
        if (userMap != null && userMap.isEmpty()) {
            return;
        }
        //区服筛选
        List<String> serverIdList = gameServerService.listServerId(param.getGameId(), param.getServerName());
        Map<Long, CpDTO> cpMap = cpService.cpMap();
        //相关用户id
        Map<Long, AgentDTO> agentMap = agentDTOList.stream().collect(Collectors.toMap(AgentDTO::getId, Function.identity()));
        Set<Long> userIdSet = userMap == null ? null : userMap.keySet();
        //下载查询
        WebExcelUtil.httpExport(response, "玩家角色", GameUserRoleExcelVO.class, ((pageNumber, pageSize) -> {
            //查询订单
            return page(new Page<>(pageNumber, pageSize), new QueryWrapper<GameUserRole>().lambda()
                    .in(GameUserRole::getGameId, gameMap.keySet())
                    .in(CollectionUtils.isNotEmpty(userIdSet), GameUserRole::getUserId, userIdSet)
                    .in(CollectionUtils.isNotEmpty(serverIdList), GameUserRole::getServerId, serverIdList)
                    .like(Strings.isNotBlank(param.getRoleName()), GameUserRole::getRoleName, param.getRoleName())
                    .eq(Objects.equals(param.getIsRecharge(), Boolean.FALSE), GameUserRole::getRechargeCount, 0)
                    .eq(Strings.isNotBlank(param.getOs()), GameUserRole::getOs, param.getOs())
                    .gt(Objects.equals(param.getIsRecharge(), Boolean.TRUE), GameUserRole::getRechargeCount, 0)
                    .gt(param.getVipLevel() != null && param.getVipLevel() > 10, GameUserRole::getRoleVipLevel, param.getVipLevel())
                    .eq(param.getVipLevel() != null && param.getVipLevel() <= 10, GameUserRole::getRoleVipLevel, param.getVipLevel())
                    .le(param.getEndDate() != null, GameUserRole::getCreateTime, param.getEndDate() == null ? null : LocalDateTime.of(param.getEndDate(), LocalTime.MAX))
                    .ge(param.getBeginDate() != null, GameUserRole::getCreateTime, param.getBeginDate() == null ? null : LocalDateTime.of(param.getBeginDate(), LocalTime.MIN))
                    .le(param.getRechargeEndDate() != null, GameUserRole::getLastRechargeTime, param.getRechargeEndDate() == null ? null : LocalDateTime.of(param.getRechargeEndDate(), LocalTime.MAX))
                    .ge(param.getRechargeBeginDate() != null, GameUserRole::getLastRechargeTime, param.getRechargeBeginDate() == null ? null : LocalDateTime.of(param.getRechargeBeginDate(), LocalTime.MIN))
                    .le(param.getRoleLevelMax() != null, GameUserRole::getRoleLevel, param.getRoleLevelMax())
                    .ge(param.getRoleLevelMin() != null, GameUserRole::getRoleLevel, param.getRoleLevelMin())
                    .apply(param.getRegPayIntervalTimeMax() != null, "if(last_recharge_time is not null, TIMESTAMPDIFF(minute, reg_time, last_recharge_time), null) <= {0}", param.getRegPayIntervalTimeMax())
                    .apply(param.getRegPayIntervalTimeMin() != null, "if(last_recharge_time is not null, TIMESTAMPDIFF(minute, reg_time, last_recharge_time), null) >= {0}", param.getRegPayIntervalTimeMin())
                    .orderByDesc(GameUserRole::getCreateTime)
            ).convert(u -> this.toVo(u, userMap, gameMap, cpMap, agentMap)).getRecords()
                    .stream().map(gameUserRoleListVO -> BeanUtil.copy(gameUserRoleListVO, GameUserRoleExcelVO.class))
                    .collect(Collectors.toList());
        }), ExcelUtil.DEFAULT_MAX_DATA_SIZE);
    }
}
