package org.jebot.scheduled;

import cn.hutool.core.date.DateUtil;
import com.pengrad.telegrambot.TelegramBot;
import com.pengrad.telegrambot.request.SendMessage;
import com.pengrad.telegrambot.response.SendResponse;
import lombok.extern.slf4j.Slf4j;
import org.jebot.constant.Constant;
import org.jebot.handler.HandlerManager;
import org.jebot.handler.dto.BotMessage;
import org.jebot.models.jebot.BotAccountBook;
import org.jebot.models.jebot.BotGroup;
import org.jebot.models.jebot.BotWarn;
import org.jebot.models.xxpay.MchAccount;
import org.jebot.models.xxpay.PayOrder;
import org.jebot.repository.jebot.BotAccountBookRepository;
import org.jebot.repository.jebot.BotGroupRepository;
import org.jebot.repository.jebot.BotWarnRepository;
import org.jebot.repository.xxpay.MchAccountRepository;
import org.jebot.repository.xxpay.PayOrderRepository;
import org.jebot.repository.xxpay.TransOrderRepository;
import org.jebot.service.dto.UpdateBalance;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Scheduled;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static org.jebot.constant.Constant.DATA_TYPE_MERCHANT;
import static org.jebot.util.DateUtil.getTodayMidnight;
import static org.jebot.util.DateUtil.getYesnight;

@Slf4j
@Configuration
public class MchScheduled {

    @Resource
    TelegramBot telegramBot;
    public HandlerManager handlerManager;

    @Resource
    private BotWarnRepository botWarnRepository;

    @Resource
    private BotGroupRepository botGroupRepository;

    @Resource
    private PayOrderRepository payOrderRepository;

    @Resource
    private TransOrderRepository transOrderRepository;

    @Resource
    private MchAccountRepository mchAccountRepository;

    @Resource
    private BotAccountBookRepository botAccountBookRepository;

    @Scheduled(cron = "*/30 * * * * *")
    public void insufficientBalanceWarning() {
        log.info("定时任务开始执行");
        // 定时任务逻辑
        List<BotGroup> botGroups = botGroupRepository.findAllByAgentWarningThresholdOrPaymentWarningThresholdGreaterThanZero();
        // 过滤出商户群组
        List<BotGroup> mchGroups = botGroups.stream().filter(botGroup -> Constant.DATA_TYPE_MERCHANT.equals(botGroup.getDataType())).collect(Collectors.toList());
        if (!mchGroups.isEmpty()) {
            List<Long> mchIds = mchGroups.stream().map(BotGroup::getDataId).collect(Collectors.toList());
            List<MchAccount> mchAccounts = mchAccountRepository.findByMchIds(mchIds);
            if (mchAccounts.isEmpty()) {
                return;
            }
            Map<Long, MchAccount> mchAccountMap = mchAccounts.stream()
                    .collect(Collectors.toMap(MchAccount::getMchId, mchAccount -> mchAccount));

            for (BotGroup mchGroup : mchGroups) {
                MchAccount mchAccount = mchAccountMap.get(mchGroup.getDataId());
                if (mchAccount == null || mchAccount.getStatus() != 1) {
                    continue;
                }
                if (mchGroup.getPaymentWarningThreshold() < 1 && mchGroup.getAgentWarningThreshold() < 1) {
                    continue;
                }
                BotAccountBook accountBook = botAccountBookRepository.findByBelongIdAndType(mchGroup.getDataId(), Constant.DATA_TYPE_MERCHANT);
                if (accountBook == null) {
                    continue;
                }
                if (mchGroup.getPaymentWarningThreshold() > 0) {
                    BigDecimal totalPayOrderAmount = payOrderRepository.findPayOrderAmountByMchIdAndCreateTime(Long.valueOf(mchGroup.getDataId()), getTodayMidnight(new Date()));
                    if (totalPayOrderAmount == null) {
                        continue;
                    }

                    BigDecimal paymentBalance = BigDecimal.valueOf(accountBook.getPaymentBalance()).movePointRight(Constant.AMOUNT_MOVE_POINT);

                    // 计算差额
                    BigDecimal difference = paymentBalance.subtract(totalPayOrderAmount);

                    // 计算百分比
                    BigDecimal percentage = totalPayOrderAmount
                            .divide(paymentBalance, 2, RoundingMode.HALF_UP)
                            .movePointRight(Constant.AMOUNT_MOVE_POINT);
                    percentage = BigDecimal.valueOf(100).subtract(percentage);
                    if (percentage.doubleValue() < mchGroup.getPaymentWarningThreshold()) {
                        //30分钟内已经发送过预警消息，跳过预警
                        BotWarn botWarn = botWarnRepository.findByDataIdAndWarnType(mchGroup.getDataId(), Constant.PAYMENT, Constant.DATA_TYPE_MERCHANT);
                        if (botWarn != null && botWarn.getUpdateTime().after(DateUtil.offsetMinute(new Date(), -30))) {
                            continue;
                        }
                        SendMessage sendMessage = new SendMessage(mchGroup.getGroupId(), "预付余额不足,请及时充值 " +
                                "\n差额比例: " + percentage +
                                "%\n当前余额: " + accountBook.getPaymentBalance() +
                                "\n已用额度: " + totalPayOrderAmount.movePointLeft(Constant.AMOUNT_MOVE_POINT) +
                                "\n剩余额度: " + difference.movePointLeft(Constant.AMOUNT_MOVE_POINT));
                        SendResponse execute = telegramBot.execute(sendMessage);
                        if (execute.isOk()) {
                            if (botWarn == null) {
                                botWarn = new BotWarn();
                                botWarn.setDataId(mchGroup.getDataId());
                                botWarn.setWarnType(Constant.PAYMENT);
                                botWarn.setDataType(Constant.DATA_TYPE_MERCHANT);
                                botWarn.setUpdateTime(new Date());
                                botWarnRepository.save(botWarn);
                            } else {
                                botWarn.setUpdateTime(new Date());
                                botWarnRepository.save(botWarn);
                            }
                            log.info("成功发送余额不足预警消息,商户ID为:" + mchGroup.getDataId() + ",群组ID为:" + mchGroup.getGroupId());
                        } else {
                            log.error("发送余额不足预警消息失败,商户ID为:" + mchGroup.getDataId() + ",群组ID为:" + mchGroup.getGroupId());
                        }

                    }
                }
                if (mchGroup.getAgentWarningThreshold() > 0) {
                    BigDecimal totalTransOrderAmount = transOrderRepository.findTransOrderAmountByMchIdAndCreateTime(Long.valueOf(mchGroup.getDataId()), DateUtil.formatDateTime(getTodayMidnight(new Date())));
                    if (totalTransOrderAmount == null) {
                        continue;
                    }
                    BigDecimal agentBalance = BigDecimal.valueOf(accountBook.getAgentBalance()).movePointRight(Constant.AMOUNT_MOVE_POINT);
                    // 计算差额
                    BigDecimal difference = agentBalance.subtract(totalTransOrderAmount);
                    // 计算百分比
                    BigDecimal percentage = totalTransOrderAmount
                            .divide(agentBalance, 2, RoundingMode.HALF_UP)
                            .movePointRight(Constant.AMOUNT_MOVE_POINT);
                    percentage = BigDecimal.valueOf(100).subtract(percentage);
                    if (percentage.doubleValue() < mchGroup.getAgentWarningThreshold()) {
                        //15分钟内已经发送过预警消息，跳过预警
                        BotWarn botWarn = botWarnRepository.findByDataIdAndWarnType(mchGroup.getDataId(), Constant.AGENT, Constant.DATA_TYPE_MERCHANT);
                        if (botWarn != null && botWarn.getUpdateTime().after(DateUtil.offsetMinute(new Date(), -15))) {
                            continue;
                        }
                        SendMessage sendMessage = new SendMessage(mchGroup.getGroupId(), "代付余额不足,请及时充值 " +
                                "\n差额比例: " + percentage +
                                "%\n当前余额: " + accountBook.getAgentBalance() +
                                "\n已用额度: " + totalTransOrderAmount.movePointLeft(Constant.AMOUNT_MOVE_POINT) +
                                "\n剩余额度: " + difference.movePointLeft(Constant.AMOUNT_MOVE_POINT));
                        SendResponse execute = telegramBot.execute(sendMessage);
                        if (execute.isOk()) {
                            if (botWarn == null) {
                                botWarn = new BotWarn();
                                botWarn.setDataId(mchGroup.getDataId());
                                botWarn.setWarnType(Constant.AGENT);
                                botWarn.setDataType(Constant.DATA_TYPE_MERCHANT);
                                botWarn.setUpdateTime(new Date());
                                botWarnRepository.save(botWarn);
                            } else {
                                botWarn.setUpdateTime(new Date());
                                botWarnRepository.save(botWarn);
                            }
                            log.info("成功发送余额不足预警消息,商户ID为:" + mchGroup.getDataId() + ",群组ID为:" + mchGroup.getGroupId());
                        } else {
                            log.error("发送余额不足预警消息失败,商户ID为:" + mchGroup.getDataId() + ",群组ID为:" + mchGroup.getGroupId());
                        }

                    }

                }
            }

        }
    }


    // 每日0:06触发结算
    @Scheduled(cron = "0 6 0 * * ?")
    public void dailyMchSettlement() {
        log.info("定时任务开始：每日商户结算");

        Date endDate = getYesnight(); // 前一天 23:59:59
        Date todayMidnight = getTodayMidnight(endDate); // 前一天 00:00:00

        List<BotGroup> botGroups = handlerManager.getGroupRepository()
                .findAllByAgentWarningThresholdOrPaymentWarningThresholdGreaterThanZero();

        List<BotGroup> mchGroups = botGroups.stream()
                .filter(botGroup -> Constant.DATA_TYPE_MERCHANT.equals(botGroup.getDataType()))
                .collect(Collectors.toList());

        if (mchGroups.isEmpty()) {
            log.info("没有商户群组");
            return;
        }

        List<Long> mchIds = mchGroups.stream().map(BotGroup::getDataId).collect(Collectors.toList());
        List<MchAccount> mchAccounts = handlerManager.getMchAccountRepository().findByMchIds(mchIds);

        if (mchAccounts.isEmpty()) {
            log.info("没有商户账户数据");
            return;
        }

        Map<Long, MchAccount> mchAccountMap = mchAccounts.stream()
                .collect(Collectors.toMap(MchAccount::getMchId, mchAccount -> mchAccount));

        StringBuilder messageText = new StringBuilder();

        for (BotGroup mchGroup : mchGroups) {
            MchAccount mchAccount = mchAccountMap.get(mchGroup.getDataId());
            if (mchAccount == null) {
                messageText.append(mchGroup.getDataName()).append("[").append(mchGroup.getDataId()).append("]: 商户不存在\n");
                continue;
            }

            if (mchAccount.getStatus() != 1) {
                messageText.append(mchAccount.getName()).append(": 商户状态异常\n");
                continue;
            }

            List<PayOrder> payOrderList = handlerManager.getPayOrderRepository()
                    .findSuccessPayOrderByMchIdAndCreateTime(mchGroup.getDataId(), todayMidnight, endDate);

            if (payOrderList.isEmpty()) {
                messageText.append(mchAccount.getName()).append(": 无订单数据\n");
                continue;
            }

            if (SettlementMch(null, mchGroup, payOrderList, todayMidnight, endDate)) {
                messageText.append(mchAccount.getName()).append(": 结算成功\n");
            } else {
                messageText.append(mchAccount.getName()).append(": 结算失败\n");
            }

            // 防止发送消息过快
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
            // 发送结算结果到管理员群或指定群
            SendMessage sendMessage = new SendMessage(mchGroup.getGroupId(), messageText.toString());
            SendResponse execute = telegramBot.execute(sendMessage);
            if (!execute.isOk()) {
                log.error("每日结算发送消息失败, 错误信息: {}", execute.description());
            } else {
                log.info("每日结算发送消息成功, 结算记录: {}", messageText);
            }
        }
    }


    private boolean SettlementMch(BotMessage message, BotGroup mchGroup, List<PayOrder> payOrderList, Date todayMidnight, Date endDate) {

        StringBuilder stringBuilder = new StringBuilder();

        // 计算总金额（未扣手续费）
        BigDecimal totalAmount = payOrderList.stream()
                .map(PayOrder::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 成功总笔数
        long totalOrders = payOrderList.size();

        // 扣除手续费后的总跑量
        BigDecimal totalAmountByMchRate = payOrderList.stream()
                .map(order -> BigDecimal.ONE
                        .subtract(order.getMchRate().movePointLeft(Constant.AMOUNT_MOVE_POINT))
                        .multiply(order.getAmount()))
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        stringBuilder.append(DateUtil.formatDate(endDate)).append("账单,请核对:\n");
        stringBuilder.append("总跑量: ").append(totalAmount.movePointLeft(Constant.AMOUNT_MOVE_POINT).doubleValue()).append("\n");
        stringBuilder.append("成功笔数: ").append(totalOrders).append("\n");
        stringBuilder.append("扣除手续费总跑量: ").append(totalAmountByMchRate.movePointLeft(Constant.AMOUNT_MOVE_POINT).doubleValue()).append("\n");

        // 扣除金额（手续费）
        // 下发金额 = 总跑量 - 手续费
        BigDecimal deductionAmount = totalAmountByMchRate.movePointLeft(Constant.AMOUNT_MOVE_POINT);


        // ================= 按费率分组汇总 =================
        stringBuilder.append("按费率统计:\n");

        Map<BigDecimal, List<PayOrder>> groupedByMchRate = payOrderList.stream()
                .collect(Collectors.groupingBy(PayOrder::getMchRate));

        groupedByMchRate.entrySet().stream()
                .sorted(Map.Entry.comparingByKey()) // 按费率排序
                .forEach(entry -> {
                    BigDecimal mchRate = entry.getKey();
                    BigDecimal amount = entry.getValue().stream()
                            .map(PayOrder::getAmount)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);

                    stringBuilder.append("费率").append(mchRate.doubleValue())
                            .append(": ")
                            .append(amount.movePointLeft(Constant.AMOUNT_MOVE_POINT).doubleValue())
                            .append("\n");
                });

        // ================= 发送账单 =================
        SendMessage sendMessage = new SendMessage(mchGroup.getGroupId(), stringBuilder.toString());
        SendResponse execute = message.getTelegramBot().execute(sendMessage);
        if (!execute.isOk()) {
            log.error("一键结算发送消息失败, 错误信息: {}", execute.description());
            return false;
        } else {
            // ================= 更新商户账本 =================
            BotAccountBook accountBook = handlerManager.getAccountBookRepository()
                    .findByBelongIdAndType(mchGroup.getDataId(), DATA_TYPE_MERCHANT);

            if (accountBook == null) {
                accountBook = new BotAccountBook();
                accountBook.setBelongId(mchGroup.getDataId());
                accountBook.setType(DATA_TYPE_MERCHANT);
                accountBook.setPaymentBalance(0);
                accountBook.setAgentBalance(0);
                handlerManager.getAccountBookRepository().save(accountBook);
            }

            log.info("一键结算发送消息成功, 群组ID: {}, 结算记录: {}", mchGroup.getGroupId(), stringBuilder.toString());

            double oldPaymentBalance = accountBook.getPaymentBalance();
            double newPaymentBalance = BigDecimal.valueOf(oldPaymentBalance)
                    .subtract(deductionAmount).doubleValue();

            BotMessage botMessage = new BotMessage();
            botMessage.setBotGroup(mchGroup);
            botMessage.setBotUser(message.getBotUser());

            try {
                UpdateBalance updateMerchantPaymentBalance = new UpdateBalance();
                updateMerchantPaymentBalance.setId(accountBook.getId());
                updateMerchantPaymentBalance.setOldBalance(oldPaymentBalance);
                updateMerchantPaymentBalance.setNewBalance(newPaymentBalance);
                updateMerchantPaymentBalance.setAmount(deductionAmount.doubleValue());
                updateMerchantPaymentBalance.setMessage(botMessage);

                handlerManager.getAccountBookService()
                        .updatePaymentBalanceByIdAndPaymentBalance(updateMerchantPaymentBalance);

                sendMessage = new SendMessage(mchGroup.getGroupId(),
                        String.format("下发提醒\n下发金额: %.2f\n下发前: %.2f\n下发后: %.2f",
                                deductionAmount.doubleValue(), oldPaymentBalance, newPaymentBalance));

            } catch (Exception e) {
                log.error("更新商户群组账本失败,群组ID:{},群组名称:{},用户ID:{},用户名称:{},金额:{},错误信息:{}",
                        message.getBotGroup().getDataId(),
                        message.getBotGroup().getDataName(),
                        message.getBotUser().getUserId(),
                        message.getBotUser().getUserName(),
                        deductionAmount.doubleValue(),
                        e.getMessage());
                e.printStackTrace();
                sendMessage = new SendMessage(message.getMessage().chat().id(),
                        "下发处理失败,请手动处理");
            } finally {
                if (sendMessage != null) {
                    message.getTelegramBot().execute(sendMessage);
                    log.info("一键结算发送消息成功, 群组ID: {}, 结算记录: {}", message.getMessage().chat().id(), sendMessage);
                }
            }
            return true;
        }
    }

}
