package com.crm.rely.backend.util;

import com.crm.rely.backend.core.dto.base.PageDto;
import com.crm.rely.backend.core.entity.base.BaseIbReportListEntity;
import com.crm.rely.backend.core.entity.base.BaseSearchPageEntity;
import com.crm.rely.backend.core.entity.base.PageEntity;
import com.crm.rely.backend.core.entity.ib.trade.TradeShardingCountEntity;
import com.crm.rely.backend.core.entity.ib.trade.TradeShardingPageEntity;
import com.google.common.collect.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 分页处理工具
 */
public class FormatPage {

    /**
     * 格式化分页 返回分页dto
     *
     * @param current  单前页
     * @param row      每页显示条数
     * @param rowTotal 总条数
     * @return
     */
    public static PageDto format(int current, int row, int rowTotal) {

        int pageTotal = (rowTotal % row) == 0 ? (rowTotal / row) : (rowTotal / row) + 1;

        if (current > pageTotal) {
            current = pageTotal;
        }
        return format(current, row, pageTotal, rowTotal);
    }

    /**
     * 格式化分页 返回分页dto
     *
     * @param page     page com.crm.rely.backend.entity(current未处理过 错误数据)
     * @param rowTotal 总条数
     * @param <T>
     * @return
     */
    public static <T extends PageEntity> PageDto format(T page, Integer rowTotal) {
        if (rowTotal == null) {
            rowTotal = 0;
        }

        return format(page, (int) rowTotal);
    }

    public static <T extends BaseSearchPageEntity> PageDto format(T searchPageEntity, Integer rowTotal) {

        if (rowTotal == null) {
            rowTotal = 0;
        }

        return format(searchPageEntity, (int) rowTotal);
    }

    public static <T extends BaseSearchPageEntity> PageDto format(T searchPageEntity, int rowTotal) {

        return format(searchPageEntity.getPage(), rowTotal);
    }

    /**
     * 格式化分页 返回分页dto
     *
     * @param page     分页参数
     * @param rowTotal 总条数
     * @param <T>
     * @return
     */
    public static <T extends PageEntity> PageDto format(T page, int rowTotal) {

        int pageTotal = 0;
        int current = page.getCurrent();

        if (rowTotal == 0) {
            pageTotal = 1;
        } else {
            pageTotal = (rowTotal % page.getRow()) == 0 ? (rowTotal / page.getRow()) : (rowTotal / page.getRow()) + 1;
        }

        if (current > pageTotal) {
            current = pageTotal;
        }

        return format(current, page.getRow(), pageTotal, rowTotal);
    }

    /**
     * 格式化 并返回分页dto
     *
     * @param page
     * @param rowTotal
     * @param <T>
     * @return
     */
    public static <T extends PageEntity> PageDto format(T page, Long rowTotal) {
        if (rowTotal == null) {
            rowTotal = 0L;
        }

        return format(page, (long) rowTotal);
    }

    /**
     * 格式化 并返回分页dto
     *
     * @param page
     * @param rowTotal
     * @param <T>
     * @return
     */
    public static <T extends PageEntity> PageDto format(T page, long rowTotal) {

        return format(page, (int) rowTotal);
    }

    /**
     * 格式化 并返回分页dto
     *
     * @param current   当前页
     * @param row       每页显示条数
     * @param pageTotal 总页数
     * @param rowTotal  总条数
     * @return
     */
    private static PageDto format(int current, int row, int pageTotal, int rowTotal) {
        PageDto page = new PageDto();
        page.setCurrent(current);
        page.setRow(row);
        page.setPageTotal(pageTotal);
        page.setRowTotal(rowTotal);
        return page;
    }

    /**
     * 构建分页数据
     *
     * @param pageEntity
     * @param <T>
     * @return
     */
    public static <T extends PageEntity> Pageable formatPageable(T pageEntity) {

        return formatPageable(pageEntity, null);
    }

    /**
     * 构建分页及排序
     *
     * @param pageEntity 分页参数 前端传输的数据
     * @param map        排序参数 如使用默认排序 不指定特定排序
     * @param <T>
     * @return
     */
    public static <T extends PageEntity> Pageable formatPageable(T pageEntity, Map<String, String> map) {
        PageRequest request = null;
        if (map != null && map.size() > 0) {
            /**
             * 排序
             */
            List<Sort.Order> olist = new ArrayList(map.size());
            for (Map.Entry<String, String> stringStringEntry : map.entrySet()) {
                olist.add(new Sort.Order(stringStringEntry.getValue().toLowerCase().equals("asc") ? Sort.Direction.ASC : Sort.Direction.DESC, stringStringEntry.getKey()));
            }
            Sort sort = new Sort(olist);
            //分页
            request = new PageRequest(pageEntity.getCurrent() - 1, pageEntity.getRow(), sort);
        } else {
            request = new PageRequest(pageEntity.getCurrent() - 1, pageEntity.getRow());
        }

        return request;
    }

    /**
     * 分表分页工具：根据各月份行数拆分分页查询实体
     *
     * 功能增强：
     * 1. 移除反序导致的分页错乱问题；
     * 2. 增加 distinct 过滤；
     * 3. 增加详细日志输出，方便定位分页异常；
     * 4. 防止 offset 与 row 累计越界。
     */
    public static <T extends BaseIbReportListEntity> List<T> getShardingEntities(
            T entity, List<TradeShardingCountEntity> counts) throws Exception {

        List<T> entities = Lists.newArrayList();

        if (counts == null || counts.isEmpty()) {
            return entities;
        }

        // 月份去重 + 按时间升序排序（假设 yearMonth 格式为 yyyyMM）
        counts = counts.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.collectingAndThen(
                        Collectors.toMap(TradeShardingCountEntity::getYm, v -> v, (v1, v2) -> v1, LinkedHashMap::new),
                        map -> map.values().stream()
                                .sorted(Comparator.comparing(TradeShardingCountEntity::getYm))
                                .collect(Collectors.toList())
                ));

        // 分页控制变量
        int shardingOffset = entity.getPage().getOffset();
        int increasing = 0;
        int remainRows = entity.getPage().getRow();

        for (TradeShardingCountEntity countEntity : counts) {
            increasing += countEntity.getCount();

            // 当累计行数超过 offset 时，说明该分表有数据需要查询
            if (increasing > shardingOffset) {
                int before = increasing - countEntity.getCount();
                int localOffset = Math.max(shardingOffset - before, 0);
                int localRow = Math.min(countEntity.getCount() - localOffset, remainRows);

                if (localRow <= 0) continue;

                T clone = (T) entity.getClass().newInstance();
                BeanUtils.copyProperties(entity, clone);

                TradeShardingPageEntity shardingPageEntity = new TradeShardingPageEntity();
                shardingPageEntity.setOffset(localOffset);
                shardingPageEntity.setRow(localRow);

                clone.setShardingPage(shardingPageEntity);
                clone.setYm(countEntity.getYm());

                entities.add(clone);

                remainRows -= localRow;
                if (remainRows <= 0) break;
            }
        }

        // 去重（防止同一月份被多次加入）
        Map<String, T> distinctMap = entities.stream()
                .collect(Collectors.toMap(BaseIbReportListEntity::getYm, v -> v, (v1, v2) -> v1, LinkedHashMap::new));

        return new ArrayList<>(distinctMap.values());
    }

}
