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


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.AdsRoleAmountRateParentMapper;
import com.zanxiang.game.gs.data.serve.pojo.dto.RolePayDTO;
import com.zanxiang.game.gs.data.serve.pojo.entity.game.parent.AdsRoleAmountRateParent;
import com.zanxiang.game.gs.data.serve.pojo.vo.PageVO;
import com.zanxiang.game.gs.data.serve.pojo.vo.RolePayVO;
import com.zanxiang.game.gs.data.serve.service.IAdsRoleAmountRateParentService;
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.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.mybatisflex.core.query.QueryMethods.sum;
import static com.zanxiang.game.gs.data.serve.pojo.entity.game.parent.table.AdsRoleAmountRateParentTableDef.ADS_ROLE_AMOUNT_RATE_PARENT;

/**
 * 游戏GS管理-GS角色付费留存 服务层实现。
 *
 * @author shaosong
 * @since 1.0
 */
@Service
public class AdsRoleAmountRateParentServiceImpl extends ServiceImpl<AdsRoleAmountRateParentMapper, AdsRoleAmountRateParent> implements IAdsRoleAmountRateParentService {
    @Resource
    private ISysUserService sysUserService;

    @Override
    public PageVO<RolePayVO, Row> rolePayOfPage(RolePayDTO dto) {
        QueryWrapper rolePayWrapper = getRolePayWrapper(dto);
        Page<RolePayVO> paginate = getMapper().paginateAs(dto.getPageNum(), dto.getPageSize(), rolePayWrapper, RolePayVO.class);
        if (0 == paginate.getTotalRow()) {
            return PageVO.empty(dto);
        }
        List<RolePayVO> records = paginate.getRecords();
        Set<Long> gsIdList = records.stream().map(RolePayVO::getGsId).collect(Collectors.toSet());
        //GS名称查询
        Map<Long, String> sysUserMap = CollectionUtils.isEmpty(gsIdList) ? null : sysUserService.getSysUserMap(gsIdList);
        records.forEach(item -> {
            item.setGsName(sysUserMap != null ? sysUserMap.get(item.getGsId()) : null);
            item.setDtDiff(DateUtil.intervalOfDays(item.getDt(), LocalDate.now()));
        });
        return new PageVO<>(paginate);
    }

    @Override
    public RolePayVO rolePayTotal(RolePayDTO dto) {
        QueryWrapper rolePayWrapper = getRolePayTotalWrapper(dto);
        return getMapper().selectOneByQueryAs(rolePayWrapper, RolePayVO.class);
    }

    private QueryWrapper getRolePayTotalWrapper(RolePayDTO dto) {
        return QueryWrapper.create()
                .from(ADS_ROLE_AMOUNT_RATE_PARENT)
                .select(getDayN())
                .select(sum(ADS_ROLE_AMOUNT_RATE_PARENT.ROLE_AMOUNT_NUM).as(ADS_ROLE_AMOUNT_RATE_PARENT.ROLE_AMOUNT_NUM.getName()))
                .select(sum(ADS_ROLE_AMOUNT_RATE_PARENT.ORDER_COUNT).as(ADS_ROLE_AMOUNT_RATE_PARENT.ORDER_COUNT.getName()))
                .select(sum(ADS_ROLE_AMOUNT_RATE_PARENT.TOTAL_AMOUNT).as(ADS_ROLE_AMOUNT_RATE_PARENT.TOTAL_AMOUNT.getName()))
                .select(sum(ADS_ROLE_AMOUNT_RATE_PARENT.ROLE_NUM).as(ADS_ROLE_AMOUNT_RATE_PARENT.ROLE_NUM.getName()))
                .select("ROUND(IF(SUM(role_amount_num) > 0 , SUM(total_amount) / SUM(role_amount_num), 0), 4) AS gs_arppu")
                .select("ROUND(IF(SUM(order_count) > 0 , SUM(total_amount) / SUM(order_count), 0), 4) AS gs_avg")
                .select("ROUND(IF(SUM(role_num) > 0 , SUM(role_amount_num) / SUM(role_num), 0), 4) AS gs_rate")
                .ge(AdsRoleAmountRateParent::getDt, dto.getDtBegin(), null != dto.getDtBegin())
                .le(AdsRoleAmountRateParent::getDt, dto.getDtEnd(), null != dto.getDtEnd())
                .in(AdsRoleAmountRateParent::getGsId, dto.getGsIdList(), CollectionUtils.isNotEmpty(dto.getGsIdList()));
    }

    private String getDayN() {
        StringBuilder currDayN = new StringBuilder(StringUtils.EMPTY);
        for (int day = 1; day <= 90; day++) {
            String dayN = "da" + day;
            daySplit(currDayN, dayN);
        }
        for (int month = 4; month <= 12; month++) {
            String mN = "m" + month;
            daySplit(currDayN, mN);
        }
        String total = "total";
        daySplit(currDayN, total);
        // 移除最后一个逗号和空格
        if (currDayN.length() > 0) {
            currDayN.setLength(currDayN.length() - 2);
        }
        //返回结果
        return currDayN.toString();
    }

    private void daySplit(StringBuilder totalDayN, String dayN) {
        totalDayN.append(" CONCAT_WS('/', ")
                .append("IFNULL(SUM(SPLIT_PART(").append(dayN).append(", '/', 1)), 0), ")
                .append("IFNULL(SUM(SPLIT_PART(").append(dayN).append(", '/', 2)), 0), ")
                .append("IFNULL(SUM(SPLIT_PART(").append(dayN).append(", '/', 3)), 0), ")
                .append("IFNULL(SUM(SPLIT_PART(").append(dayN).append(", '/', 4)), 0), ")
                .append("ROUND(IF(SUM(SPLIT_PART(").append(dayN).append(", '/', 1)) > 0, ")
                .append("SUM(SPLIT_PART(").append(dayN).append(", '/', 2)) / SUM(SPLIT_PART(").append(dayN).append(", '/', 1)), 0), 4), ")
                .append("ROUND(IF(SUM(role_num) > 0, SUM(SPLIT_PART(").append(dayN).append(", '/', 1)) / SUM(role_num), 0), 4), ")
                .append("ROUND(IF(SUM(role_num) > 0, SUM(SPLIT_PART(").append(dayN).append(", '/', 2)) / SUM(role_num), 0), 4)) ")
                .append("as ").append(dayN).append(", ");
    }

    private QueryWrapper getRolePayWrapper(RolePayDTO dto) {
        return QueryWrapper.create()
                .from(ADS_ROLE_AMOUNT_RATE_PARENT)
                .select(ADS_ROLE_AMOUNT_RATE_PARENT.ALL_COLUMNS)
                .ge(AdsRoleAmountRateParent::getDt, dto.getDtBegin(), null != dto.getDtBegin())
                .le(AdsRoleAmountRateParent::getDt, dto.getDtEnd(), null != dto.getDtEnd())
                .in(AdsRoleAmountRateParent::getGsId, dto.getGsIdList(), CollectionUtils.isNotEmpty(dto.getGsIdList()))
                .orderBy(dto.getSortFiled(), dto.getSortAsc());
    }
}