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

import com.google.common.base.CaseFormat;
import com.zanxiang.game.data.serve.component.DataPowerComponent;
import com.zanxiang.game.data.serve.pojo.dto.GameServerDayDTO;
import com.zanxiang.game.data.serve.pojo.dto.GameServerDayTotalDTO;
import com.zanxiang.game.data.serve.pojo.entity.AdsGameServerDay;
import com.zanxiang.game.data.serve.pojo.enums.OrderByEnum;
import com.zanxiang.game.data.serve.pojo.vo.GameServerDayTotalVO;
import com.zanxiang.game.data.serve.pojo.vo.GameServerDayVO;
import com.zanxiang.game.data.serve.pojo.vo.GameServerTrendVO;
import com.zanxiang.game.data.serve.service.IGameServerService;
import com.zanxiang.game.data.serve.utils.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.pager.Pager;
import org.nutz.dao.sql.Criteria;
import org.nutz.dao.sql.Sql;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tianhua
 * @time 2023/8/14
 * @Description 游戏区服接口逻辑处理
 **/
@Slf4j
@Service
public class GameServerServiceImpl implements IGameServerService {

    //存储映射的List
    private static final List<Tuple2<Field,Field>> dayNFieldMapList;
    private static final List<Tuple2<Field,Field>> dayNTotalFieldMapList;

    static {
        //解析游戏区服的dayN映射
        Map<String, Field> fieldMap = new HashMap<>();
        List<Field> dayNFieldList = new ArrayList<>();
        Class<?> tempClazz = GameServerDayVO.class;
        while (tempClazz != null) {
            //得到所有的field
            Field[] fields = tempClazz.getDeclaredFields();
            for (Field field : fields) {
                if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
                    continue;
                }
                //map里面存储了所有的field
                fieldMap.put(field.getName(), field);
                if (field.getType() == GameServerTrendVO.class) {
                    //list里面只存储了 Trend 相关的field
                    dayNFieldList.add(field);
                }
            }
            tempClazz = tempClazz.getSuperclass();
        }
        if (dayNFieldList.isEmpty()) {
            dayNFieldMapList = Collections.emptyList();
        } else {
            dayNFieldMapList = new ArrayList<>(dayNFieldList.size());
            for (Field dayNField : dayNFieldList) {
                dayNField.setAccessible(true);
                Field sourceField = fieldMap.get(dayNField.getName().replace("Trend", ""));
                sourceField.setAccessible(true);
                if (sourceField != null) {
                    dayNFieldMapList.add(Tuples.of(sourceField, dayNField));
                }
            }
        }

        //游戏区服总计dayN映射
        Map<String, Field> fieldTotalMap = new HashMap<>();
        List<Field> dayNTotalFieldList = new ArrayList<>();
        Class<?> tempTotalClazz = GameServerDayTotalVO.class;
        while (tempTotalClazz != null) {
            //得到所有的field
            Field[] fields = tempTotalClazz.getDeclaredFields();
            for (Field field : fields) {
                if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
                    continue;
                }
                //map里面存储了所有的field
                fieldTotalMap.put(field.getName(), field);
                if (field.getType() == GameServerTrendVO.class) {
                    //list里面只存储了 Trend 相关的field
                    dayNTotalFieldList.add(field);
                }
            }
            tempTotalClazz = tempTotalClazz.getSuperclass();
        }
        if (dayNTotalFieldList.isEmpty()) {
            dayNTotalFieldMapList = Collections.emptyList();
        } else {
            dayNTotalFieldMapList = new ArrayList<>(dayNTotalFieldList.size());
            for (Field dayNTotalField : dayNTotalFieldList) {
                dayNTotalField.setAccessible(true);
                Field sourceField = fieldTotalMap.get(dayNTotalField.getName().replace("Trend", ""));
                sourceField.setAccessible(true);
                if (sourceField != null) {
                    dayNTotalFieldMapList.add(Tuples.of(sourceField, dayNTotalField));
                }
            }
        }
    }

    @Autowired
    private Dao dao;
    @Autowired
    private DataPowerComponent dataPowerComponent;

    /**
     * 游戏区服数据
     *
     * @param dto 前端传递的查询参数
     * @return page
     */
    @Override
    public Page<GameServerDayVO> getGameServerDataDay(GameServerDayDTO dto) {
        List<Long> gameIds = dto.getGameId() == null ? dataPowerComponent.getSubGameIdList() : Collections.singletonList(dto.getGameId());

        //创建查询条件
        Criteria cri = Cnd.cri();
        if (gameIds != null) {
            //拼接游戏ID查询条件
            cri.where().andInList("game_id", gameIds);
        }
        if (dto.getServerId() != null) {
            //拼接区服ID查询条件
            cri.where().andEquals("server_id", dto.getServerId());
        }
        if (StringUtils.isNotBlank(dto.getServerName())) {
            //拼接区服名称查询条件
            cri.where().andLike("server_name", dto.getServerName());
        }
        if (dto.getBeginDate() != null && dto.getEndDate() != null) {
            //拼接开服时间查询条件
            cri.where().andBetween("dt", dto.getBeginDate(), dto.getEndDate());
        }
        if (StringUtils.isNotBlank(dto.getSourceSystem())) {
            //拼接sdk来源
            cri.where().andEquals("source_system", dto.getSourceSystem());
        }
        //添加排序条件
        //拼接排序条件，如果没有排序条件给默认值
        if (StringUtils.isBlank(dto.getSortType())) {
            dto.setSortType(OrderByEnum.DESC.getOrderType());
        }
        if (StringUtils.isBlank(dto.getSortFiled())) {
            cri.getOrderBy().orderBy("dt", dto.getSortType());
            cri.getOrderBy().orderBy("server_id", dto.getSortType());
        } else {
            cri.getOrderBy().orderBy(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, dto.getSortFiled()), dto.getSortType());
        }
        //创建sql语句查询数据
        Sql sql = Sqls.create(gameServerDaySql() + cri);
        //设置自定义回传对象
        sql.setCallback(Sqls.callback.entities());
        sql.setEntity(dao.getEntity(GameServerDayVO.class));
        //设置分页对象
        Pager pager = dao.createPager(dto.getPageNum(), dto.getPageSize());
        sql.setPager(pager);
        //执行sql
        dao.execute(sql);
        //设置总记录数
        pager.setRecordCount(dao.count(AdsGameServerDay.class, cri));
        List<GameServerDayVO> tempList = sql.getList(GameServerDayVO.class);
        List<GameServerDayVO> list = tempList.stream().map(vo -> {
                formatDayN(vo);
                return vo;
        }).collect(Collectors.toList());
        //返回结果
        return new Page<>(list, pager);
    }

    /**
     * 游戏区服数据总计
     *
     * @param dto 前端传递的查询参数
     * @return vo
     */
    @Override
    public GameServerDayTotalVO getGameServerDataDayTotal(GameServerDayTotalDTO dto) {
        List<Long> gameIds = dto.getGameId() == null ? dataPowerComponent.getSubGameIdList() : Collections.singletonList(dto.getGameId());
        //创建查询条件
        Criteria cri = Cnd.cri();
        if (gameIds != null) {
            //拼接游戏ID查询条件
            cri.where().andInList("game_id", gameIds);
        }
        if (dto.getServerId() != null) {
            //拼接区服ID查询条件
            cri.where().andEquals("server_id", dto.getServerId());
        }
        if (StringUtils.isNotBlank(dto.getServerName())) {
            //拼接区服名称查询条件
            cri.where().andLike("server_name", dto.getServerName());
        }
        if (dto.getBeginDate() != null && dto.getEndDate() != null) {
            //拼接开服时间查询条件
            cri.where().andBetween("dt", dto.getBeginDate(), dto.getEndDate());
        }
        if (StringUtils.isNotBlank(dto.getSourceSystem())) {
            //拼接sdk来源
            cri.where().andEquals("source_system", dto.getSourceSystem());
        }
        //创建sql语句查询数据
        Sql sql = Sqls.create(gameServerDayTotalSql() + cri);
        //设置自定义回传对象
        sql.setCallback(Sqls.callback.entity());
        sql.setEntity(dao.getEntity(GameServerDayTotalVO.class));
        //执行sql
        dao.execute(sql);
        //得到查询的结果
        GameServerDayTotalVO vo = sql.getObject(GameServerDayTotalVO.class);
        if (StringUtils.isNotBlank(vo.getDa1())) {
            formatTotalDayN(vo);
        }
        //返回结果
        return vo;
    }

    /**
     * 将vo中的原始String数据修改为一个对象
     * @param vo 展示给前端的游戏区服数据
     */
    private void formatDayN(GameServerDayVO vo) {
        if (CollectionUtils.isEmpty(dayNFieldMapList)) {
            return;
        }
        dayNFieldMapList.forEach(dayNFieldMap -> {
            try {
                String[] temps = ((String) dayNFieldMap.getT1().get(vo)).split("/");
                dayNFieldMap.getT2().set(vo, GameServerTrendVO.builder()
                        .regNum(Long.parseLong(temps[0]))
                        .roleNum(Long.parseLong(temps[1]))
                        .activeNum(Long.parseLong(temps[2]))
                        .amountNum(Long.parseLong(temps[3]))
                        .amount(new BigDecimal(temps[4]))
                        .rollServerNum(Long.parseLong(temps[5]))
                        .rollServerAmountNum(Long.parseLong(temps[6]))
                        .rollServerAmount(new BigDecimal(temps[7]))
                        .rollServerAmountRate(new BigDecimal(temps[8]))
                        .build()
                );
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        });
    }

    /**
     * 将vo中的原始String数据修改为一个对象
     * @param vo 展示给前端的游戏区服数据总计
     */
    private void formatTotalDayN(GameServerDayTotalVO vo) {
        if (CollectionUtils.isEmpty(dayNTotalFieldMapList)) {
            return;
        }
        dayNTotalFieldMapList.forEach(dayNTotalFieldMap -> {
            try {
                String[] temps = ((String) dayNTotalFieldMap.getT1().get(vo)).split("/");
                //付费金额
                BigDecimal amount = new BigDecimal(temps[4]);
                //滚服付费金额
                BigDecimal rollServerAmount = new BigDecimal(temps[7]);
                //设置trend对象
                dayNTotalFieldMap.getT2().set(vo, GameServerTrendVO.builder()
                        .regNum(Long.parseLong(temps[0]))
                        .roleNum(Long.parseLong(temps[1]))
                        .activeNum(Long.parseLong(temps[2]))
                        .amountNum(Long.parseLong(temps[3]))
                        .amount(amount)
                        .rollServerNum(Long.parseLong(temps[5]))
                        .rollServerAmountNum(Long.parseLong(temps[6]))
                        .rollServerAmount(rollServerAmount)
                        .rollServerAmountRate(amount.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO :
                                rollServerAmount.divide(amount, 4, RoundingMode.HALF_UP))
                        .build()
                );
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        });
    }

    /**
     * 计算总计一栏的daN数据
     * @return String
     */
    private String trendDay() {
        StringBuilder daySql = new StringBuilder(StringUtils.EMPTY);
        //拼接da1-da90 sql
        for (int i = 1; i <= 90; i++) {
            daySql.append("""
                    CONCAT(
                    	SUM(SPLIT_PART(da%s, '/', 1)), '/',
                    	SUM(SPLIT_PART(da%s, '/', 2)), '/',
                    	SUM(SPLIT_PART(da%s, '/', 3)), '/',
                    	SUM(SPLIT_PART(da%s, '/', 4)), '/',
                    	SUM(SPLIT_PART(da%s, '/', 5)), '/',
                    	SUM(SPLIT_PART(da%s, '/', 6)), '/',
                    	SUM(SPLIT_PART(da%s, '/', 7)), '/',
                    	SUM(SPLIT_PART(da%s, '/', 8))
                    ) as da%s ,
                    """.formatted(i, i, i, i, i, i, i, i, i));
        }
        //拼接m4-m12 sql
        for (int i = 4; i <= 12; i++) {
            daySql.append("""
                    CONCAT(
                    	SUM(SPLIT_PART(m%s, '/', 1)), '/',
                    	SUM(SPLIT_PART(m%s, '/', 2)), '/',
                    	SUM(SPLIT_PART(m%s, '/', 3)), '/',
                    	SUM(SPLIT_PART(m%s, '/', 4)), '/',
                    	SUM(SPLIT_PART(m%s, '/', 5)), '/',
                    	SUM(SPLIT_PART(m%s, '/', 6)), '/',
                    	SUM(SPLIT_PART(m%s, '/', 7)), '/',
                    	SUM(SPLIT_PART(m%s, '/', 8))
                    ) as m%s ,
                    """.formatted(i, i, i, i, i, i, i, i, i));
        }
        //拼接total
        daySql.append("""
                    CONCAT(
                    	SUM(SPLIT_PART(total, '/', 1)), '/',
                    	SUM(SPLIT_PART(total, '/', 2)), '/',
                    	SUM(SPLIT_PART(total, '/', 3)), '/',
                    	SUM(SPLIT_PART(total, '/', 4)), '/',
                    	SUM(SPLIT_PART(total, '/', 5)), '/',
                    	SUM(SPLIT_PART(total, '/', 6)), '/',
                    	SUM(SPLIT_PART(total, '/', 7)), '/',
                    	SUM(SPLIT_PART(total, '/', 8))
                    ) as total
                    """);

        return daySql.toString();
    }

    /**
     * 游戏区服数据SQL
     * @return String
     */
    private String gameServerDaySql() {
        return """
                SELECT
                    dt,
                    source_system,
                    server_id,
                    server_name,
                    game_id,
                    game_name,
                    classify,
                    out_total_num,
                    out_total_amount_num,
                    out_total_amount,
                    out_total_rate,
                    total_role_num,
                    total_reg_num,
                    total_amount_num,
                    total_amount,
                    da1,
                    da2,
                    da3,
                    da4,
                    da5,
                    da6,
                    da7,
                    da8,
                    da9,
                    da10,
                    da11,
                    da12,
                    da13,
                    da14,
                    da15,
                    da16,
                    da17,
                    da18,
                    da19,
                    da20,
                    da21,
                    da22,
                    da23,
                    da24,
                    da25,
                    da26,
                    da27,
                    da28,
                    da29,
                    da30,
                    da31,
                    da32,
                    da33,
                    da34,
                    da35,
                    da36,
                    da37,
                    da38,
                    da39,
                    da40,
                    da41,
                    da42,
                    da43,
                    da44,
                    da45,
                    da46,
                    da47,
                    da48,
                    da49,
                    da50,
                    da51,
                    da52,
                    da53,
                    da54,
                    da55,
                    da56,
                    da57,
                    da58,
                    da59,
                    da60,
                    da61,
                    da62,
                    da63,
                    da64,
                    da65,
                    da66,
                    da67,
                    da68,
                    da69,
                    da70,
                    da71,
                    da72,
                    da73,
                    da74,
                    da75,
                    da76,
                    da77,
                    da78,
                    da79,
                    da80,
                    da81,
                    da82,
                    da83,
                    da84,
                    da85,
                    da86,
                    da87,
                    da88,
                    da89,
                    da90,
                    m4,
                    m5,
                    m6,
                    m7,
                    m8,
                    m9,
                    m10,
                    m11,
                    m12,
                    total
                FROM
                    game_ads.ads_game_server_day
                """;
    }

    /**
     * 游戏区服数据总计SQL
     * @return String
     */
    private String gameServerDayTotalSql() {
        return """
                SELECT
                    IFNULL(SUM(out_total_num), 0) as out_total_num,
                    IFNULL(SUM(out_total_amount_num), 0) as out_total_amount_num,
                    IFNULL(SUM(out_total_amount), 0) as out_total_amount,
                    ROUND(IF(SUM(total_amount) > 0, SUM(out_total_amount) / SUM(total_amount), 0), 4) as out_total_rate,
                    IFNULL(SUM(total_role_num), 0) as total_role_num,
                    IFNULL(SUM(total_reg_num), 0) as total_reg_num,
                    IFNULL(SUM(total_amount_num), 0) as total_amount_num,
                    IFNULL(SUM(total_amount), 0) as total_amount,
                """ + trendDay() +
                """
                FROM
                    game_ads.ads_game_server_day
                """;
    }


}
