package com.zanxiang.game.gs.data.serve.service.impl;


import com.google.common.base.CaseFormat;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.zanxiang.game.gs.data.serve.dao.mapper.game.parent.AdsServerRankingParentMapper;
import com.zanxiang.game.gs.data.serve.pojo.dto.ServeManageDTO;
import com.zanxiang.game.gs.data.serve.pojo.entity.game.parent.AdsServerRankingParent;
import com.zanxiang.game.gs.data.serve.pojo.vo.PageVO;
import com.zanxiang.game.gs.data.serve.pojo.vo.ServeManageVO;
import com.zanxiang.game.gs.data.serve.service.IAdsServerRankingParentService;
import com.zanxiang.game.gs.data.serve.service.IGameServerSonMergeService;
import com.zanxiang.game.gs.data.serve.service.ISysUserService;
import com.zanxiang.module.util.DateUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

import static com.zanxiang.game.gs.data.serve.pojo.entity.game.parent.table.AdsServerRankingParentTableDef.ADS_SERVER_RANKING_PARENT;

/**
 * GS区服付费留存(游戏GS管理) 服务层实现。
 *
 * @author shaosong
 * @since 1.0
 */
@Service
public class AdsServerRankingParentServiceImpl extends ServiceImpl<AdsServerRankingParentMapper, AdsServerRankingParent> implements IAdsServerRankingParentService {
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private IGameServerSonMergeService serverSonMergeService;

    @Override
    public PageVO<ServeManageVO, Row> serveManage(ServeManageDTO dto) {
        if (StringUtils.isBlank(dto.getSortFiled())) {
            dto.setSortFiled(ADS_SERVER_RANKING_PARENT.SON_SERVER_AMOUNT.getName());
        } else {
            String column = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, dto.getSortFiled());
            dto.setSortFiled(column);
        }
        QueryWrapper wrapper = getServeManageWrapper(dto);

        Page<ServeManageVO> paginate = getMapper().paginateAs(dto.getPageNum(), dto.getPageSize(), wrapper, ServeManageVO.class);
        if (0 == paginate.getTotalRow()) {
            return PageVO.empty(dto);
        }
        List<ServeManageVO> records = paginate.getRecords();

        Set<String> serverIdList = records.stream().map(ServeManageVO::getServerId).collect(Collectors.toSet());

        Set<Long> gsIdList = new HashSet<>();
        records.stream().map(ServeManageVO::getGsIds)
                .filter(item -> StringUtils.isNotBlank(item) && !"null".equals(item))
                .forEach(gsIds -> {
                    List<String> gsIdStr = Arrays.asList(gsIds.split(","));
                    Set<Long> collect = gsIdStr.stream().map(Long::valueOf).collect(Collectors.toSet());
                    gsIdList.addAll(collect);
                });
        // 当前页的游戏id+区服id
        List<String> gameAndServeIdList = records.stream().map(item -> item.getParentGameId() + "_" + item.getServerId()).collect(Collectors.toList());
        QueryWrapper rankWrapper = getRankWrapper(dto, gameAndServeIdList);
        Map<Integer, Map<String, List<ServeManageVO>>> rankMap = listAs(rankWrapper, ServeManageVO.class)
                .stream()
                .collect(Collectors.groupingBy(ServeManageVO::getParentGameId, Collectors.groupingBy(ServeManageVO::getServerId)));
        // GS名称查询
        Map<Long, String> sysUserMap = CollectionUtils.isEmpty(gsIdList) ? null : sysUserService.getSysUserMap(gsIdList);
        // 是否原始服
        Map<Long, Map<String, Integer>> serverOriginMap = serverSonMergeService.gameServerOriginMap(dto.getSourceSystem(), serverIdList);
        records.forEach(record -> {
            // 基础信息
            String gsIds = record.getGsIds();
            if (StringUtils.isNotBlank(gsIds) && !"null".equals(gsIds)) {
                List<String> gsIdStr = Arrays.asList(gsIds.split(","));
                record.setGsStatus(gsIdStr.size() == 1 ? 1 : 2);
                Set<String> collect = gsIdStr.stream().map(Long::valueOf)
                        .map(gsId -> sysUserMap != null ? sysUserMap.get(gsId) : null)
                        .collect(Collectors.toSet());
                record.setGsName(StringUtils.join(collect, ","));
            }
            Integer original = null == serverOriginMap.get(record.getSuperGameId()) ? null : serverOriginMap.get(record.getSuperGameId()).get(record.getServerId());
            record.setOriginServer(null == original ? null : 1 == original);

            record.setStartDiff(DateUtil.intervalOfDays(record.getStartTime(), LocalDate.now()));
            record.setServeDiff(record.getEndTime().isBefore(LocalDate.now()) ? DateUtil.intervalOfDays(record.getStartTime(), record.getEndTime())
                    : DateUtil.intervalOfDays(record.getStartTime(), LocalDate.now()));
            record.setServeStatus(record.getEndTime().isBefore(LocalDate.now()));
            List<ServeManageVO.CombatRank> combatRankList = rankMap.get(record.getParentGameId()).get(record.getServerId())
                    .stream()
                    .filter(vo -> null != vo.getCombatNum())
                    .map(vo -> ServeManageVO.CombatRank.builder()
                            .combatAmount(vo.getCombatAmount())
                            .combatCountry(vo.getCombatCountry())
                            .combatNum(vo.getCombatNum())
                            .combatRoleId(vo.getCombatRoleId())
                            .combatRoleLevel(vo.getCombatRoleLevel())
                            .combatRoleName(vo.getCombatRoleName())
                            .combatTotalRoleCombatNum(vo.getCombatTotalRoleCombatNum())
                            .build())
                    .sorted(Comparator.comparingLong(ServeManageVO.CombatRank::getCombatNum))
                    .collect(Collectors.toList());

            record.setCombatRankList(combatRankList);

            List<ServeManageVO.AmountRank> amountRankList = rankMap.get(record.getParentGameId()).get(record.getServerId())
                    .stream()
                    .filter(vo -> null != vo.getAmountNum())
                    .map(vo -> ServeManageVO.AmountRank.builder()
                            .amountCountry(vo.getAmountCountry())
                            .amountNum(vo.getAmountNum())
                            .amountRoleId(vo.getAmountRoleId())
                            .amountRoleLevel(vo.getAmountRoleLevel())
                            .amountRoleName(vo.getAmountRoleName())
                            .amountRoleTotalAmount(vo.getAmountRoleTotalAmount())
                            .amountTotalRoleCombatNum(vo.getAmountTotalRoleCombatNum())
                            .build())
                    .sorted(Comparator.comparingLong(ServeManageVO.AmountRank::getAmountNum))
                    .collect(Collectors.toList());

            record.setAmountRankList(amountRankList);
        });
        return new PageVO<>(paginate);
    }

    private QueryWrapper getServeManageWrapper(ServeManageDTO dto) {
        QueryWrapper queryWrapper =  QueryWrapper.create()
                .from(ADS_SERVER_RANKING_PARENT)
                .select(ADS_SERVER_RANKING_PARENT.START_TIME)
                .select(ADS_SERVER_RANKING_PARENT.PARENT_GAME_ID)
                .select(ADS_SERVER_RANKING_PARENT.SERVER_ID)
                .select(ADS_SERVER_RANKING_PARENT.SUPER_GAME_ID)
                .select(ADS_SERVER_RANKING_PARENT.END_TIME)
                .select(ADS_SERVER_RANKING_PARENT.PARENT_GAME_NAME)
                .select(ADS_SERVER_RANKING_PARENT.SERVER_NAME)
                .select(ADS_SERVER_RANKING_PARENT.GS_IDS)
                .select(ADS_SERVER_RANKING_PARENT.TOTAL_ROLE_NUM)
                .select(ADS_SERVER_RANKING_PARENT.TOTAL_AMOUNT_NUM)
                .select(ADS_SERVER_RANKING_PARENT.TOTAL_AMOUNT_COUNT)
                .select(ADS_SERVER_RANKING_PARENT.TOTAL_AMOUNT)
                .select(ADS_SERVER_RANKING_PARENT.AMOUNT_RATE)
                .select(ADS_SERVER_RANKING_PARENT.SON_ROLE_NUM)
                .select(ADS_SERVER_RANKING_PARENT.SON_SERVER_AMOUNT_COUNT)
                .select(ADS_SERVER_RANKING_PARENT.SON_SERVER_AMOUNT)
                .select(ADS_SERVER_RANKING_PARENT.SON_AMOUNT_RATE)
                .groupBy(ADS_SERVER_RANKING_PARENT.START_TIME)
                .groupBy(ADS_SERVER_RANKING_PARENT.PARENT_GAME_ID)
                .groupBy(ADS_SERVER_RANKING_PARENT.SERVER_ID)
                .groupBy(ADS_SERVER_RANKING_PARENT.SUPER_GAME_ID)
                .groupBy(ADS_SERVER_RANKING_PARENT.END_TIME)
                .groupBy(ADS_SERVER_RANKING_PARENT.PARENT_GAME_NAME)
                .groupBy(ADS_SERVER_RANKING_PARENT.SERVER_NAME)
                .groupBy(ADS_SERVER_RANKING_PARENT.GS_IDS)
                .groupBy(ADS_SERVER_RANKING_PARENT.TOTAL_ROLE_NUM)
                .groupBy(ADS_SERVER_RANKING_PARENT.TOTAL_AMOUNT_NUM)
                .groupBy(ADS_SERVER_RANKING_PARENT.TOTAL_AMOUNT_COUNT)
                .groupBy(ADS_SERVER_RANKING_PARENT.TOTAL_AMOUNT)
                .groupBy(ADS_SERVER_RANKING_PARENT.AMOUNT_RATE)
                .groupBy(ADS_SERVER_RANKING_PARENT.SON_ROLE_NUM)
                .groupBy(ADS_SERVER_RANKING_PARENT.SON_SERVER_AMOUNT)
                .groupBy(ADS_SERVER_RANKING_PARENT.SON_SERVER_AMOUNT_COUNT)
                .groupBy(ADS_SERVER_RANKING_PARENT.SON_AMOUNT_RATE)
                .orderBy(dto.getSortFiled(), dto.getSortAsc());
        condition(dto, queryWrapper);
        return queryWrapper;
    }

    private QueryWrapper getRankWrapper(ServeManageDTO dto, List<String> gameAndServeIdList) {
        return QueryWrapper.create()
                .from(ADS_SERVER_RANKING_PARENT)
                .and(ADS_SERVER_RANKING_PARENT.SOURCE_SYSTEM.eq(dto.getSourceSystem()))
                .in("CONCAT_WS('_', parent_game_id, server_id)", gameAndServeIdList);
    }

    private static void condition(ServeManageDTO dto, QueryWrapper queryWrapper) {
        queryWrapper.eq(AdsServerRankingParent::getSourceSystem, dto.getSourceSystem())
                .ge(AdsServerRankingParent::getStartTime, dto.getServerStartBegin(), null != dto.getServerStartBegin())
                .le(AdsServerRankingParent::getStartTime, dto.getServerStartEnd(), null != dto.getServerStartEnd())
                .ge(AdsServerRankingParent::getStartTime, dto.getServeDayBegin(), null != dto.getServeDayBegin())
                .le(AdsServerRankingParent::getEndTime, dto.getServeDayEnd(), null != dto.getServeDayEnd())
                .eq(AdsServerRankingParent::getSuperGameId, dto.getSuperGameId(), null != dto.getSuperGameId())
                .eq(AdsServerRankingParent::getParentGameId, dto.getParentGameId(), null != dto.getParentGameId())
                .in(AdsServerRankingParent::getServerId, dto.getServerIdList(), CollectionUtils.isNotEmpty(dto.getServerIdList()))
                .ge(AdsServerRankingParent::getEndTime, LocalDate.now(), null != dto.getServeStatus() && 1 == dto.getServeStatus())
                .le(AdsServerRankingParent::getEndTime, LocalDate.now(), null != dto.getServeStatus() && 2 == dto.getServeStatus());
        if (CollectionUtils.isNotEmpty(dto.getGsIdList())) {
            StringBuilder gsSql = new StringBuilder();
            dto.getGsIdList().forEach(gsId -> {
                gsSql.append(String.format(" FIND_IN_SET(%s, gs_ids) > 0", gsId));
                gsSql.append(" OR ");
            });
            gsSql.setLength(gsSql.length() - 4);
            queryWrapper.and(gsSql.toString());
        }
        if (null != dto.getGsStatus() && 1 == dto.getGsStatus()) {
            queryWrapper.and("gs_ids != 'null' and LENGTH(gs_ids) - LENGTH(REPLACE(gs_ids, ',', '')) + 1 = 1");
        }

        if (null != dto.getGsStatus() && 2 == dto.getGsStatus()) {
            queryWrapper.and("gs_ids != 'null' and LENGTH(gs_ids) - LENGTH(REPLACE(gs_ids, ',', '')) + 1 > 1");
        }
    }
}