package com.ruoyi.ss.transactionBill.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.ss.suit.domain.SuitVO;
import com.ruoyi.ss.suit.domain.enums.SuitFeeMode;
import com.ruoyi.ss.suit.domain.enums.SuitFeeType;
import com.ruoyi.ss.suit.domain.enums.SuitTimeUnit;
import com.ruoyi.ss.transactionBill.domain.vo.PrepayPriceVO;
import com.ruoyi.ss.transactionBill.domain.vo.TransactionBillVO;
import com.ruoyi.ss.vip.domain.VipVO;
import com.ruoyi.ss.vip.utils.VipUtil;

/**
 * @author wjh
 * 2024/12/24
 */
public class RechargeUtils {

    /**
     * 转换为充值电量
     */
    public static BigDecimal toRechargeEle(TransactionBillVO bill) {
        if (bill == null) {
            return BigDecimal.ZERO;
        }
        // 普通充值
        if (SuitFeeType.singleList().contains(bill.getSuitFeeType())) {
            // 计算周期数
            long round = calcRound(bill);
            return BigDecimal.valueOf(bill.getSuitTime() * round);
        }
        // 分时段充值
        else {
            // 按照应用的最低电价来计算电量
            List<Integer> indexes = bill.getSuitGearTime().stream().distinct().collect(Collectors.toList());
            BigDecimal minAmount = null;
            for (Integer index : indexes) {
                BigDecimal amount = bill.getSuitGearAmount().get(index);
                if (minAmount == null || amount.compareTo(minAmount) < 0) {
                    minAmount = amount;
                }
            }
            // 若没有配置则默认0.01元
            if (minAmount == null || minAmount.compareTo(BigDecimal.ZERO) <= 0) {
                minAmount = new BigDecimal("0.01");
            }

            return bill.getMoney().divide(minAmount, 2, RoundingMode.HALF_UP);
        }
    }

    /**
     * 转换为充值秒
     */
    public static long toRechargeSeconds(TransactionBillVO bill) {
        if (bill == null) {
            return 0L;
        }
        // 普通充值
        if (SuitFeeType.singleList().contains(bill.getSuitFeeType())) {
            long round = calcRound(bill);
            return toSecondSuitTime(bill) * round;
        }
        // 分时段充值
        else {
            return calcUsageSeconds(bill.getMoney(), LocalDateTime.now(), bill.getSuitGearAmount(), bill.getSuitGearTime());
        }
    }

    /**
     * 根据金额计算可使用时长（秒）
     * @param amount 金额
     * @param startTime 开始时间
     * @param suitGearAmount 时段金额列表
     * @param suitGearTime 时段配置列表
     * @return 可使用的时长（秒）
     */
    private static long calcUsageSeconds(BigDecimal amount, LocalDateTime startTime, List<BigDecimal> suitGearAmount, List<Integer> suitGearTime) {

        // 剩余金额
        BigDecimal remainAmount = amount;
        // 累计秒数
        long totalSeconds = 0;
        // 初始时间
        LocalDateTime currentTime = startTime.withMinute(0).withSecond(0);

        BigDecimal minAmount = new BigDecimal("0.01");

        while (remainAmount.compareTo(BigDecimal.ZERO) > 0) {
            // 当前小时的每分钟费用
            BigDecimal minuteAmount = suitGearAmount.get(suitGearTime.get(currentTime.getHour()))
                    .divide(BigDecimal.valueOf(60), 2, RoundingMode.HALF_UP);

            // 如果是开始的第一个小时，需要计算实际开始时间的分钟数
            int availableMinutes = 60;
            if (currentTime.equals(startTime.withMinute(0).withSecond(0))) {
                availableMinutes = 60 - startTime.getMinute();
            }

            // 当前时段最多可以使用的金额，最低不允许小于0.01元
            BigDecimal maxAmount = minuteAmount.multiply(BigDecimal.valueOf(availableMinutes));
            if (maxAmount.compareTo(minAmount) < 0) {
                maxAmount = minAmount;
            }

            if (remainAmount.compareTo(maxAmount) >= 0) {
                // 如果剩余金额足够支付整个时段
                totalSeconds += availableMinutes * 60;
                remainAmount = remainAmount.subtract(maxAmount);
            } else {
                // 如果剩余金额不足支付整个时段，计算可用分钟数
                int minutes = remainAmount.divide(minuteAmount, 0, RoundingMode.FLOOR).intValue();
                totalSeconds += minutes * 60L;
                remainAmount = BigDecimal.ZERO;
            }

            currentTime = currentTime.plusHours(1);
        }

        return totalSeconds;
    }

    /**
     * 转换为套餐秒
     */
    public static long toSecondSuitTime(TransactionBillVO bill) {
        SuitTimeUnit unit = SuitTimeUnit.getByValue(bill.getSuitTimeUnit());
        if (unit == null) {
            unit = SuitTimeUnit.MINUTE;
        }
        long time = bill.getSuitTime() == null ? 0 : bill.getSuitTime();
        return time * unit.getConversion();
    }

    /**
     * 计算周期数
     */
    private static long calcRound(TransactionBillVO bill) {
        int round = 1;
        if (bill == null || bill.getSuitFeeMode() == null || bill.getSuitFeeType() == null) {
            return round;
        }
        // 若为智能单次，则计算出押金最大支持多少次，向上取整
        if (SuitFeeMode.SMART.getMode().equals(bill.getSuitFeeMode()) && SuitFeeType.singleList().contains(bill.getSuitFeeType())) {
            round = bill.getSuitDeposit().divide(bill.getSuitPrice(), 0, RoundingMode.UP).intValue();
        }
        return round;
    }

    /**
     * 获取分时段订单指定时段的金额
     */
    public static BigDecimal getGearAmount(TransactionBillVO bill, int hour) {
        if (bill == null || CollectionUtils.isEmptyElement(bill.getSuitGearAmount()) || CollectionUtils.isEmptyElement(bill.getSuitGearTime()) || hour < 0) {
            return null;
        }

        return bill.getSuitGearAmount().get(bill.getSuitGearTime().get(hour));
    }

    public static PrepayPriceVO calcRechargePrePayPrice(VipVO vip, SuitVO suit) {
        if (suit == null) {
            return null;
        }
        // 结果
        PrepayPriceVO vo = new PrepayPriceVO();

        // 原价
        if (SuitFeeMode.SMART.getMode().equals(suit.getFeeMode())) {
            // 智能收费，收取押金
            vo.setOriginalPrice(suit.getDeposit());
        } else {
            // 单次收费，收取本金
            vo.setOriginalPrice(suit.getPrice());
        }
        vo.setPayPrice(vo.getOriginalPrice());


        // 计算优惠后的金额
        if (vip != null) {
            BigDecimal payPrice = VipUtil.calcDiscountAmount(vip.getDiscount(), vo.getPayPrice());
            vo.setPayPrice(payPrice);
        } 

        // 计算已优惠金额
        BigDecimal discountAmount = vo.getOriginalPrice().subtract(vo.getPayPrice());
        vo.setDiscountAmount(discountAmount);
        return vo;
    }
}
