package com.zhongshu.card.server.core.service.pay;

import com.github.microservice.components.data.base.page.PageableModel;
import com.github.microservice.core.util.bean.BeanUtil;
import com.github.microservice.pay.client.model.ledger.GeneralLedgerQueryModel;
import com.github.microservice.pay.client.model.ledger.GeneralLedgerTreeModel;
import com.github.microservice.pay.client.model.ledger.TransactionLogModel;
import com.github.microservice.pay.client.model.ledger.transaction.*;
import com.github.microservice.pay.client.ret.ResultContent;
import com.github.microservice.pay.client.ret.ResultState;
import com.github.microservice.pay.client.service.ledger.GeneralLedgerService;
import com.github.microservice.pay.client.service.ledger.TransactionLogService;
import com.github.microservice.pay.client.type.ledger.LedgerEntry;
import com.github.microservice.pay.client.type.ledger.TransactionStatus;
import com.github.microservice.pay.client.type.ledger.TransactionType;
import com.github.microservice.types.payment.PaymentChannelType;
import com.github.microservice.types.payment.PaymentType;
import com.zhongshu.card.client.model.pay.*;
import com.zhongshu.card.client.type.PeriodType;
import com.zhongshu.card.client.type.SettleStatus;
import com.zhongshu.card.client.utils.DateUtils;
import com.zhongshu.card.server.core.domain.pay.PayAccount;
import com.zhongshu.card.server.core.service.base.SuperService;
import com.zhongshu.card.server.core.service.org.OrganizationUserServiceImpl;
import com.zhongshu.card.server.core.util.ExcelUtils;
import com.zhongshu.card.server.core.util.excel.CommonExeclParam;
import com.zhongshu.card.server.core.util.excel.CommonExeclTd;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static org.springframework.integration.IntegrationPatternType.filter;
import static org.springframework.integration.IntegrationPatternType.inbound_gateway;

@Service
@Slf4j
public class OrgOverviewService extends SuperService {

    @Autowired
    TransactionLogService transactionLogService;

    @Autowired
    GeneralLedgerService generalLedgerService;

    @Autowired
    PayAccountService payAccountService;

    @Autowired
    OrganizationUserServiceImpl organizationUserService;

    /**
     * 查询用户流水
     */
    public com.github.microservice.net.ResultContent<TransactionLogAggregateRetModel> queryAccountTreeFlow(Pageable pageable, QueryTransLogParam param){

        String userId = param.getUserId();
        String projectOid = param.getProjectOid();

        if (StringUtils.isBlank(userId)){
            userId = getCurrentUserId();
        }

        if (StringUtils.isBlank(projectOid)){
            projectOid = getCurrentProjectOid();
        }

        if (StringUtils.isBlank(projectOid)){
            return com.github.microservice.net.ResultContent.buildFail("projectOid is null");
        }

        PayAccount userParent = payAccountService.getUserParent(projectOid, userId);
        ResultContent<GeneralLedgerQueryModel> ledgerRet = generalLedgerService.get(userParent.getLedgerId());
        if (!ledgerRet.getState().equals(ResultState.Success)){
            return com.github.microservice.net.ResultContent.buildFail(ledgerRet.getMsg());
        }

        ResultContent<GeneralLedgerTreeModel> descendantRet = generalLedgerService.descendant(userParent.getLedgerId());
        if (!descendantRet.getState().equals(ResultState.Success)){
            return com.github.microservice.net.ResultContent.buildFail("获取用户账户及下级账户失败");
        }
//        GeneralLedgerTreeModel generalLedgerTreeModel = descendantRet.getContent();
//        List<GeneralLedgerTreeModel> children = generalLedgerTreeModel.getChildren();
//        List<String> childrenIdList = children.stream().map(GeneralLedgerModel::getId).toList();

        DescendantQueryTransactionLogModel descendantQueryTransactionLogModel = new DescendantQueryTransactionLogModel();
        PageableModel pageableModel = new PageableModel();
        pageableModel.setPage(pageable.getPageNumber());
        pageableModel.setSize(pageable.getPageSize());
        pageableModel.setSort("createTime");

//        descendantQueryTransactionLogModel.setGeneralLedgerId(new String[]{userParent.getLedgerId()});
        descendantQueryTransactionLogModel.setPage(pageableModel);
        descendantQueryTransactionLogModel.setParentGeneralLedgerId(userParent.getLedgerId());
        descendantQueryTransactionLogModel.setStartTime(param.getStartTime());
        descendantQueryTransactionLogModel.setEndTime(param.getEndTime());
        ResultContent<TransactionLogAggregateRetModel> aggregate = transactionLogService.aggregate(descendantQueryTransactionLogModel);
        if (aggregate.getState().equals(ResultState.Success)){
            return com.github.microservice.net.ResultContent.buildContent(aggregate.getContent());
        }
        return com.github.microservice.net.ResultContent.buildFail(aggregate.getMsg());
    }

    /**
     * 查询用户流水(按月)
     */

    /**
     * 统计机构账户余额、待结算金额、提现中金额
     */
    public BalanceOverviewModel balanceOverview(String projectOid, String oid){
        if (StringUtils.isEmpty(projectOid)){
            projectOid = getCurrentProjectOid();
        }
        if (StringUtils.isEmpty(oid)){
            oid = getCurrentOid();
        }

        BalanceOverviewModel balanceOverviewModel = new BalanceOverviewModel();
        PayAccount orgParent = payAccountService.getOrgParent(projectOid, oid);
        ResultContent<GeneralLedgerTreeModel> descendantRet = generalLedgerService.descendant(orgParent.getLedgerId());
        List<GeneralLedgerTreeModel> children = descendantRet.getContent().getChildren();
        if (children!=null && !children.isEmpty()){
            children.forEach(it->{
                PaymentChannelType paymentChannelType = PaymentChannelType.valueOf(PaymentChannelType.class, (String) it.getMeta().get("paymentChannelType"));
                if (paymentChannelType == PaymentChannelType.Settle){
                    balanceOverviewModel.setSettle(it.getBalance());
                }else if (paymentChannelType == PaymentChannelType.WaitSettle){
                    balanceOverviewModel.setWaitSettle(it.getBalance());
                }else if (paymentChannelType == PaymentChannelType.WithdrawFrozen){
                    balanceOverviewModel.setWithdrawFrozen(it.getBalance());
                }
            });
        }
        return balanceOverviewModel;
    }

    public Object realTimeOverview(String projectOid){
        if (StringUtils.isEmpty(projectOid)){
            projectOid = getCurrentProjectOid();
        }


        List<String> oidList = organizationUserService.getUserOrgListOids(getCurrentUserId(), projectOid);
        if (oidList==null || oidList.isEmpty()){
            return com.github.microservice.net.ResultContent.buildFail("未加入机构");
        }

        PayAccount waitSettleAccount = payAccountService.getOrgChildren(projectOid, oidList.get(0), PaymentChannelType.WaitSettle);

        //构建实时概况收入数据
        List<Long> yesterdayList = new ArrayList<>();
        List<Long> todayList = new ArrayList<>();

        List<TransactionLogRealTimeAggregateRetModel> yesterday = realTimeAggregate(waitSettleAccount.getLedgerId(), DateUtils.getCurrentDayStartTime().getTime() - 24 * 60 * 60 * 1000,
                DateUtils.getCurrentDayEndTime().getTime() - 24 * 60 * 60 * 1000,
                Map.of("ledgerEntry", LedgerEntry.Credit));

        List<TransactionLogRealTimeAggregateRetModel> today = realTimeAggregate(waitSettleAccount.getLedgerId(), DateUtils.getCurrentDayStartTime().getTime(),
                DateUtils.getCurrentDayEndTime().getTime(),
                Map.of("ledgerEntry", LedgerEntry.Credit));
        List<String> currentIntegralPoint = DateUtils.getCurrentIntegralPoint("yyyy-MM-dd HH");
        List<String> yesterdayIntegralPoint = DateUtils.getYesterdayIntegralPoint("yyyy-MM-dd HH");
        buildRealTimeAmountList(yesterdayList, yesterday, yesterdayIntegralPoint);
        buildRealTimeAmountList(todayList, today, currentIntegralPoint);
        Long todayAmount = todayList.stream().mapToLong(it -> {
            return it;
        }).sum();
        Long yesterdayAmount = yesterdayList.stream().mapToLong(it -> {
            return it;
        }).sum();
        //构建实时概况订单数据
        List<Long> yesterdayOrderList = new ArrayList<>();
        List<Long> todayOrderList = new ArrayList<>();

        List<TransactionLogRealTimeAggregateRetModel> yesterdayGroupByOrderNumber = realTimeByOrderNumberAggregate(waitSettleAccount.getLedgerId(), DateUtils.getCurrentDayStartTime().getTime() - 24 * 60 * 60 * 1000,
                DateUtils.getCurrentDayEndTime().getTime() - 24 * 60 * 60 * 1000,
                Map.of("ledgerEntry", LedgerEntry.Credit));

        List<TransactionLogRealTimeAggregateRetModel> todayGroupByOrderNumber = realTimeByOrderNumberAggregate(waitSettleAccount.getLedgerId(), DateUtils.getCurrentDayStartTime().getTime(),
                DateUtils.getCurrentDayEndTime().getTime(),
                Map.of("ledgerEntry", LedgerEntry.Credit));

        yesterdayOrderList = buildRealTimeAmountList(yesterdayOrderList, yesterdayGroupByOrderNumber, yesterdayIntegralPoint);
        todayOrderList = buildRealTimeAmountList(todayOrderList, todayGroupByOrderNumber, currentIntegralPoint);
        Long todayOrder = todayOrderList.stream().mapToLong(it -> {
            return it;
        }).sum();
        Long yesterdayOrder = yesterdayOrderList.stream().mapToLong(it -> {
            return it;
        }).sum();

        List<String> retIntegralPoint = DateUtils.getCurrentIntegralPoint("HH:mm");
        RealTimeOverviewModel realTimeOverviewModel = new RealTimeOverviewModel();
        //收入数据
        realTimeOverviewModel.setPoint(retIntegralPoint);
        realTimeOverviewModel.setTodayAmount(todayAmount);
        realTimeOverviewModel.setYesterdayAmount(yesterdayAmount);
        List<BigDecimal> todayListBigDecimal = todayList.stream().map(it->{
            BigDecimal bigDecimal = new BigDecimal(it);
            return bigDecimal.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        }).toList();
        realTimeOverviewModel.setTodayList(todayListBigDecimal);
        List<BigDecimal> yesterdayListBigDecimal = yesterdayList.stream().map(it->{
            BigDecimal bigDecimal = new BigDecimal(it);
            return bigDecimal.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
        }).toList();
        realTimeOverviewModel.setYesterdayList(yesterdayListBigDecimal);

        realTimeOverviewModel.setAmountChangeRate(changeRate(todayAmount, yesterdayAmount));
        //订单数据
        realTimeOverviewModel.setYesterdayOrderList(yesterdayOrderList);
        realTimeOverviewModel.setTodayOrderList(todayOrderList);
        realTimeOverviewModel.setYesterdayOrder(yesterdayOrder);
        realTimeOverviewModel.setTodayOrder(todayOrder);
        realTimeOverviewModel.setOrderChangeRate(changeRate(todayOrder, yesterdayOrder));

        BalanceOverviewModel balanceOverviewModel = balanceOverview(projectOid, oidList.get(0));
        realTimeOverviewModel.setBalanceOverview(balanceOverviewModel);
        //构建24小时大小的
        return ResultContent.buildContent(realTimeOverviewModel);
    }


    public Object queryCreditBill(Pageable pageable, PeriodQueryModel param){
        String projectOid = param.getProjectOid();
        if (StringUtils.isBlank(param.getProjectOid())){
            projectOid = getCurrentProjectOid();
        }

        PageableModel pageableModel = new PageableModel();
        pageableModel.setPage(pageable.getPageNumber());
        pageableModel.setSize(pageable.getPageSize());

        List<String> oidList = organizationUserService.getUserOrgListOids(getCurrentUserId(), projectOid);
        if (oidList==null || oidList.isEmpty()){
            return com.github.microservice.net.ResultContent.buildFail("未加入机构");
        }

        PayAccount payAccount = payAccountService.getOrgChildren(projectOid, oidList.get(0), PaymentChannelType.WaitSettle);
        GeneralLedgerQueryTransactionLogModel queryModel = new GeneralLedgerQueryTransactionLogModel();
        queryModel.setGeneralLedgerId(new String[]{payAccount.getLedgerId()});
        queryModel.setStartTime(param.getStartTime());
        queryModel.setEndTime(param.getEndTime());
        queryModel.setFilter(Map.of("transactionType",new Document("$ne", "Settle")));
        queryModel.setPage(pageableModel);

        if (param.getPeriodType().equals(PeriodType.day)){
            return transactionLogService.periodDayAggregate(queryModel);
        } else if (param.getPeriodType().equals(PeriodType.month)){
            return transactionLogService.periodMonthAggregate(queryModel);
        }else if (param.getPeriodType().equals(PeriodType.year)){
            return transactionLogService.periodYearAggregate(queryModel);
        }
        return com.github.microservice.net.ResultContent.buildFail("周期类型不存在");
    }

    public Object queryCreditBillDetail(Pageable pageable, PeriodDetailQueryModel periodDetailQueryModel){
        String projectOid = periodDetailQueryModel.getProjectOid();
        if (StringUtils.isBlank(projectOid)) {
            projectOid = getCurrentProjectOid();
        }

        List<String> oidList = organizationUserService.getUserOrgListOids(getCurrentUserId(), projectOid);
        if (oidList==null || oidList.isEmpty()){
            return com.github.microservice.net.ResultContent.buildFail("未加入机构");
        }

        PayAccount payAccount = payAccountService.getOrgChildren(projectOid, oidList.get(0), PaymentChannelType.WaitSettle);

        GeneralLedgerQueryTransactionLogModel queryModel = new GeneralLedgerQueryTransactionLogModel();

        PageableModel pageableModel = new PageableModel();
        pageableModel.setPage(pageable.getPageNumber());
        pageableModel.setSize(pageable.getPageSize());
        pageableModel.setSort("createTime");
        pageableModel.setDirection(Sort.Direction.DESC);
        queryModel.setPage(pageableModel);

        queryModel.setStartTime(periodDetailQueryModel.getStartTime());
        queryModel.setEndTime(periodDetailQueryModel.getEndTime());
        queryModel.setGeneralLedgerId(new String[]{payAccount.getLedgerId()});

        Map<String, Object> filter = new HashMap<>();
        Optional.ofNullable(periodDetailQueryModel.getTransactionLogId()).ifPresent((it) ->{
            filter.put("transactionLogId", it);
        });

        Optional.ofNullable(periodDetailQueryModel.getLedgerEntry()).ifPresent((it) ->{
            filter.put("ledgerEntry", it);
        });

        Optional.ofNullable(periodDetailQueryModel.getOrderNo()).ifPresent((it) ->{
            filter.put("orderNumber", it);
        });

        Optional.ofNullable(periodDetailQueryModel.getPaymentType()).ifPresent((it) ->{
            filter.put("meta.paymentType", it);
        });

        filter.put("transactionType",new Document("$ne", "Settle"));
        queryModel.setFilter(filter);
        return ResultContent.buildContent(transactionLogService.aggregate(queryModel).getContent().getPages());
    }

    public void exportCreditBill(HttpServletRequest request, HttpServletResponse response, PeriodDetailQueryModel periodDetailQueryModel){
        String projectOid = periodDetailQueryModel.getProjectOid();
        if (StringUtils.isBlank(projectOid)) {
            projectOid = getCurrentProjectOid();
        }

        List<String> oidList = organizationUserService.getUserOrgListOids(getCurrentUserId(), projectOid);
        if (oidList==null || oidList.isEmpty()){
            throw new RuntimeException("未加入机构");
        }

        PayAccount payAccount = payAccountService.getOrgChildren(projectOid, oidList.get(0), PaymentChannelType.WaitSettle);

        GeneralLedgerQueryTransactionLogModel queryModel = new GeneralLedgerQueryTransactionLogModel();

        queryModel.setStartTime(periodDetailQueryModel.getStartTime());
        queryModel.setEndTime(periodDetailQueryModel.getEndTime());
        queryModel.setGeneralLedgerId(new String[]{payAccount.getLedgerId()});

        Map<String, Object> filter = new HashMap<>();
        filter.put("transactionType",new Document("$ne", "Settle"));
        queryModel.setFilter(filter);
        List<TransactionLogModel> list = transactionLogService.aggregateNotPage(queryModel).getContent().getList();

        buildBillExcel(request, response, periodDetailQueryModel.getCreateDate(), list);
    }

    private static void buildBillExcel(HttpServletRequest request, HttpServletResponse response, String title, List<TransactionLogModel> list) {
        CommonExeclParam execlParam = new CommonExeclParam();
        execlParam.setTitle(String.format("%s收入账单", title));
        execlParam.setStartRow(2);

        List<Map<String, Object>> data = list.stream().map(it -> {
            Map<String, Object> map = new HashMap<>();
            map.put("id", it.getId());
            map.put("orderNo", it.getOrderNumber());
            map.put("createDate", DateUtils.paresTime(it.getCreateTime(), DateUtils.FORMAT_LONG));
            if (it.getMeta()!=null) {
                if (it.getMeta().get("paymentType") != null){
                    PaymentType paymentType = PaymentType.valueOf(it.getMeta().get("paymentType").toString());
                    map.put("paymentType", paymentType.getRemark());
                }
                if (it.getMeta().get("summary") !=null){
                    map.put("summary", it.getMeta().get("summary").toString());
                }
            }
            LedgerEntry ledgerEntry = it.getLedgerEntry();
            if (ledgerEntry.equals(LedgerEntry.Credit)) {
                map.put("ledgerEntry", "收入");
            } else if (ledgerEntry.equals(LedgerEntry.Debit)) {
                map.put("ledgerEntry", "支出");
            }
            map.put("remark", it.getRemark());
            map.put("amount", it.getAmount());
            return map;
        }).collect(Collectors.toList());
        execlParam.setDatas(data);
        List<CommonExeclTd> tds = new ArrayList<>();
        tds.add(CommonExeclTd.build("账单流水编号", "id"));
        tds.add(CommonExeclTd.build("关联订单编号", "orderNo"));
        tds.add(CommonExeclTd.build("创建时间", "createDate"));
        tds.add(CommonExeclTd.build("支付方式", "paymentType"));
        tds.add(CommonExeclTd.build("账单类型", "ledgerEntry"));
        tds.add(CommonExeclTd.build("记账摘要", "summary"));
        tds.add(CommonExeclTd.build("金额（元）", "amount"));

        execlParam.setTds(tds);
        ExcelUtils.commonExecuteExcel(request, response, execlParam);
    }

    public Object querySettleBill(Pageable pageable, PeriodQueryModel param){
        String projectOid = param.getProjectOid();
        if (StringUtils.isBlank(param.getProjectOid())){
            projectOid = getCurrentProjectOid();
        }

        PageableModel pageableModel = new PageableModel();
        pageableModel.setPage(pageable.getPageNumber());
        pageableModel.setSize(pageable.getPageSize());

        List<String> oidList = organizationUserService.getUserOrgListOids(getCurrentUserId(), projectOid);
        if (oidList==null || oidList.isEmpty()){
            return com.github.microservice.net.ResultContent.buildFail("未加入机构");
        }

        //获取已结算账本
        PayAccount settleAccount = payAccountService.getOrgChildren(projectOid, oidList.get(0), PaymentChannelType.Settle);

        GeneralLedgerQueryTransactionLogModel queryModel = new GeneralLedgerQueryTransactionLogModel();
        queryModel.setGeneralLedgerId(new String[]{settleAccount.getLedgerId()});
        queryModel.setStartTime(param.getStartTime());
        queryModel.setEndTime(param.getEndTime());
//        queryModel.setFilter(Map.of("transactionType",new Document("$ne", "Settle")));
        queryModel.setFilter(Map.of("transactionType","Settle"));
        queryModel.setPage(pageableModel);

        return transactionLogService.settleAggregate(queryModel);
    }

    public Object querySettleBillDetail(Pageable pageable, SettleDetailQueryModel settleDetailQueryModel){
        String projectOid = settleDetailQueryModel.getProjectOid();
        if (StringUtils.isBlank(projectOid)) {
            projectOid = getCurrentProjectOid();
        }

        List<String> oidList = organizationUserService.getUserOrgListOids(getCurrentUserId(), projectOid);
        if (oidList==null || oidList.isEmpty()){
            return com.github.microservice.net.ResultContent.buildFail("未加入机构");
        }

        PayAccount payAccount = payAccountService.getOrgChildren(projectOid, oidList.get(0), PaymentChannelType.WaitSettle);

        GeneralLedgerQueryTransactionLogModel queryModel = new GeneralLedgerQueryTransactionLogModel();

        PageableModel pageableModel = new PageableModel();
        pageableModel.setPage(pageable.getPageNumber());
        pageableModel.setSize(pageable.getPageSize());
        pageableModel.setSort("createTime");
        pageableModel.setDirection(Sort.Direction.DESC);
        queryModel.setPage(pageableModel);

        queryModel.setGeneralLedgerId(new String[]{payAccount.getLedgerId()});

        Map<String, Object> filter = new HashMap<>();
        Optional.ofNullable(settleDetailQueryModel.getTransactionLogId()).ifPresent((it) ->{
            filter.put("transactionLogId", it);
        });

        Optional.ofNullable(settleDetailQueryModel.getLedgerEntry()).ifPresent((it) ->{
            filter.put("ledgerEntry", it);
        });

        Optional.ofNullable(settleDetailQueryModel.getOrderNo()).ifPresent((it) ->{
            filter.put("orderNumber", it);
        });

        Optional.ofNullable(settleDetailQueryModel.getPaymentType()).ifPresent((it) ->{
            filter.put("meta.paymentType", it);
        });

        String createDate = settleDetailQueryModel.getCreateDate();
        if (StringUtils.isBlank(createDate)){
            return com.github.microservice.net.ResultContent.buildFail("createDate不能为空");
        }

        String formatCreateTime = DateUtils.paresTime(DateUtils.timeToLong(createDate, DateUtils.pattern), DateUtils.pattern);

        filter.put("meta.settleStatus", SettleStatus.Settle);
        filter.put("meta.settleTime", formatCreateTime);
        filter.put("transactionType",new Document("$ne", "Settle"));
        queryModel.setFilter(filter);
        return ResultContent.buildContent(transactionLogService.aggregate(queryModel).getContent().getPages());
    }

    public void exportSettleBill(HttpServletRequest request, HttpServletResponse response, SettleDetailQueryModel settleDetailQueryModel) {
        String projectOid = settleDetailQueryModel.getProjectOid();
        if (StringUtils.isBlank(projectOid)) {
            projectOid = getCurrentProjectOid();
        }

        List<String> oidList = organizationUserService.getUserOrgListOids(getCurrentUserId(), projectOid);
        if (oidList == null || oidList.isEmpty()) {
            throw new RuntimeException("未加入机构");
        }

        PayAccount payAccount = payAccountService.getOrgChildren(projectOid, oidList.get(0), PaymentChannelType.WaitSettle);

        GeneralLedgerQueryTransactionLogModel queryModel = new GeneralLedgerQueryTransactionLogModel();

        queryModel.setGeneralLedgerId(new String[]{payAccount.getLedgerId()});

        Map<String, Object> filter = new HashMap<>();

        String createDate = settleDetailQueryModel.getCreateDate();
        if (StringUtils.isBlank(createDate)) {
            throw new RuntimeException("createDate不能为空");
        }

        String formatCreateTime = DateUtils.paresTime(DateUtils.timeToLong(createDate, DateUtils.pattern), DateUtils.pattern);

        filter.put("meta.settleStatus", SettleStatus.Settle);
        filter.put("meta.settleTime", formatCreateTime);
        filter.put("transactionType", new Document("$ne", "Settle"));
        queryModel.setFilter(filter);
        List<TransactionLogModel> list = transactionLogService.aggregateNotPage(queryModel).getContent().getList();
        buildBillExcel(request, response, settleDetailQueryModel.getCreateDate(), list);
    }


    public Object queryWithdrawBill(Pageable pageable, PeriodQueryModel param){
        String projectOid = param.getProjectOid();
        if (StringUtils.isBlank(param.getProjectOid())){
            projectOid = getCurrentProjectOid();
        }

        PageableModel pageableModel = new PageableModel();
        pageableModel.setPage(pageable.getPageNumber());
        pageableModel.setSize(pageable.getPageSize());

        List<String> oidList = organizationUserService.getUserOrgListOids(getCurrentUserId(), projectOid);
        if (oidList==null || oidList.isEmpty()){
            return com.github.microservice.net.ResultContent.buildFail("未加入机构");
        }

        //获取已结算账本
        PayAccount settleAccount = payAccountService.getOrgChildren(projectOid, oidList.get(0), PaymentChannelType.Settle);

        GeneralLedgerQueryTransactionLogModel queryModel = new GeneralLedgerQueryTransactionLogModel();
        queryModel.setGeneralLedgerId(new String[]{settleAccount.getLedgerId()});
        queryModel.setStartTime(param.getStartTime());
        queryModel.setEndTime(param.getEndTime());

//        queryModel.setFilter(Map.of("transactionType","Withdrawal"));
        queryModel.setFilter(Map.of("transactionType",new Document("$in", List.of(TransactionType.Withdrawal, TransactionType.WithdrawRefund))));
        queryModel.setPage(pageableModel);
        return transactionLogService.withdrawAggregate(queryModel);
    }

    public Object queryWithdrawBillDetail(Pageable pageable, SettleDetailQueryModel settleDetailQueryModel){
        String projectOid = settleDetailQueryModel.getProjectOid();
        if (StringUtils.isBlank(projectOid)) {
            projectOid = getCurrentProjectOid();
        }

        List<String> oidList = organizationUserService.getUserOrgListOids(getCurrentUserId(), projectOid);
        if (oidList==null || oidList.isEmpty()){
            return com.github.microservice.net.ResultContent.buildFail("未加入机构");
        }

        PayAccount payAccount = payAccountService.getOrgChildren(projectOid, oidList.get(0), PaymentChannelType.Settle);

        GeneralLedgerQueryTransactionLogModel queryModel = new GeneralLedgerQueryTransactionLogModel();

        PageableModel pageableModel = new PageableModel();
        pageableModel.setPage(pageable.getPageNumber());
        pageableModel.setSize(pageable.getPageSize());
        pageableModel.setSort("createTime");
        pageableModel.setDirection(Sort.Direction.DESC);
        queryModel.setPage(pageableModel);

        queryModel.setGeneralLedgerId(new String[]{payAccount.getLedgerId()});

        Map<String, Object> filter = new HashMap<>();
        Optional.ofNullable(settleDetailQueryModel.getTransactionLogId()).ifPresent((it) ->{
            filter.put("transactionLogId", it);
        });

        Optional.ofNullable(settleDetailQueryModel.getLedgerEntry()).ifPresent((it) ->{
            filter.put("ledgerEntry", it);
        });

        Optional.ofNullable(settleDetailQueryModel.getOrderNo()).ifPresent((it) ->{
            filter.put("orderNumber", it);
        });

        Optional.ofNullable(settleDetailQueryModel.getPaymentType()).ifPresent((it) ->{
            filter.put("meta.paymentType", it);
        });

        String createDate = settleDetailQueryModel.getCreateDate();
        if (StringUtils.isBlank(createDate)){
            return com.github.microservice.net.ResultContent.buildFail("createDate不能为空");
        }

        Long startTime = DateUtils.timeToLong(createDate, DateUtils.pattern);

        queryModel.setStartTime(startTime);
        queryModel.setEndTime(startTime + 24*60*60*1000L);

        filter.put("transactionType",new Document("$in", List.of(TransactionType.Withdrawal, TransactionType.WithdrawRefund)));
        queryModel.setFilter(filter);
        return ResultContent.buildContent(transactionLogService.aggregate(queryModel).getContent().getPages());
    }

    public void exportWithdrawBill(HttpServletRequest request, HttpServletResponse response, SettleDetailQueryModel settleDetailQueryModel){
        String projectOid = settleDetailQueryModel.getProjectOid();
        if (StringUtils.isBlank(projectOid)) {
            projectOid = getCurrentProjectOid();
        }

        List<String> oidList = organizationUserService.getUserOrgListOids(getCurrentUserId(), projectOid);
        if (oidList==null || oidList.isEmpty()){
            throw new RuntimeException("未加入机构");
        }

        PayAccount payAccount = payAccountService.getOrgChildren(projectOid, oidList.get(0), PaymentChannelType.Settle);

        GeneralLedgerQueryTransactionLogModel queryModel = new GeneralLedgerQueryTransactionLogModel();

        queryModel.setGeneralLedgerId(new String[]{payAccount.getLedgerId()});

        Map<String, Object> filter = new HashMap<>();

        String createDate = settleDetailQueryModel.getCreateDate();
        if (StringUtils.isBlank(createDate)){
            throw new RuntimeException("createDate不能为空");
        }

        Long startTime = DateUtils.timeToLong(createDate, DateUtils.pattern);

        queryModel.setStartTime(startTime);
        queryModel.setEndTime(startTime + 24*60*60*1000L);

        filter.put("transactionType",new Document("$in", List.of(TransactionType.Withdrawal, TransactionType.WithdrawRefund)));
        queryModel.setFilter(filter);
        List<TransactionLogModel> list = transactionLogService.aggregateNotPage(queryModel).getContent().getList();
        buildBillExcel(request, response, settleDetailQueryModel.getCreateDate(), list);
    }


    private BigDecimal changeRate(Long todayAmount, Long yesterdayAmount) {
        BigDecimal amountChangeRate = BigDecimal.ZERO;
        if (yesterdayAmount != 0L){
            BigDecimal today = new BigDecimal(todayAmount);
            BigDecimal yesterday = new BigDecimal(yesterdayAmount);
            BigDecimal subtract = today.subtract(yesterday);
            BigDecimal divide = subtract.divide(yesterday, 2, BigDecimal.ROUND_HALF_UP);
            amountChangeRate = divide.movePointRight(2);
        }else {
            BigDecimal totalAmountBigDecimal = new BigDecimal(todayAmount);
            amountChangeRate = totalAmountBigDecimal.movePointRight(2);
        }
        return amountChangeRate;
    }

    private List<Long> buildRealTimeAmountList(List<Long> amountList, List<TransactionLogRealTimeAggregateRetModel> modelList, List<String> currentIntegralPoint) {
        Map<String, Long> yesterdayMap;
        if (modelList !=null){
            yesterdayMap = modelList.stream().collect(Collectors.toMap(TransactionLogRealTimeAggregateRetModel::getDateTime, TransactionLogRealTimeAggregateRetModel::getAmount));
            for (String point : currentIntegralPoint) {
                amountList.add(yesterdayMap.getOrDefault(point, 0L));
                log.info("point: {}, map: {}", point, yesterdayMap.getOrDefault(point, 0L));
            }
        }else {
            for (int i = 0; i < currentIntegralPoint.size(); i++) {
                amountList.add(0L);
            }
        }
        return amountList;
    }

    private List<TransactionLogRealTimeAggregateRetModel> realTimeAggregate(String ledgerId, Long startTime, Long endTime, Map<String, Object> filter) {
        GeneralLedgerQueryTransactionLogModel queryModel = new GeneralLedgerQueryTransactionLogModel();
        queryModel.setGeneralLedgerId(new String[]{ledgerId});
        queryModel.setStartTime(startTime);
        queryModel.setEndTime(endTime);
        queryModel.setFilter(filter);
        ResultContent<List<TransactionLogRealTimeAggregateRetModel>> realTimeAggregateRet = transactionLogService.realTimeAggregate(queryModel);
        if (realTimeAggregateRet.getState().equals(ResultState.Success)){
            return realTimeAggregateRet.getContent();
        }
        return null;
    }

    private List<TransactionLogRealTimeAggregateRetModel> realTimeByOrderNumberAggregate(String ledgerId, Long startTime, Long endTime, Map<String, Object> filter) {
        GeneralLedgerQueryTransactionLogModel queryModel = new GeneralLedgerQueryTransactionLogModel();
        queryModel.setGeneralLedgerId(new String[]{ledgerId});
        queryModel.setStartTime(startTime);
        queryModel.setEndTime(endTime);
        queryModel.setFilter(filter);
        ResultContent<List<TransactionLogRealTimeAggregateRetModel>> realTimeAggregateRet = transactionLogService.realTimeByOrderNumberAggregate(queryModel);
        if (realTimeAggregateRet.getState().equals(ResultState.Success)){
            return realTimeAggregateRet.getContent();
        }
        return null;
    }
}
