package com.sckw.transport.service;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sckw.core.common.enums.enums.ErrorCodeEnum;
import com.sckw.core.exception.BusinessPlatfromException;
import com.sckw.core.model.constant.Global;
import com.sckw.core.model.enums.ParkingChangeStrategyEnum;
import com.sckw.core.utils.CollectionUtils;
import com.sckw.core.utils.StringUtils;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.result.PageDataResult;
import com.sckw.system.api.RemoteSystemService;
import com.sckw.system.api.model.dto.res.EntCacheResDto;
import com.sckw.transport.api.model.param.ParkingWalletFeeFreezeParam;
import com.sckw.transport.api.model.vo.ParkingWalletFeeFreezeResult;
import com.sckw.transport.model.*;
import com.sckw.transport.model.enuma.WalletTypEnum;
import com.sckw.transport.model.param.*;
import com.sckw.transport.repository.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * Author: donglang
 * Time: 2026-01-05
 * Des: 收费策略 Service
 * Version: 1.0
 */

@Slf4j
@Service
@RequiredArgsConstructor
public class ParkingWalletFeeService {

    private final KwtParkingWalletFeeRepository parkingWalletFeeRepository;
    private final KwtParkingWalletFeeBalanceRepository parkingWalletFeeBalanceRepository;

    private final KwtParkingChangeStrategyRepository parkingChangeStrategyRepository;
    private final KwtParkingChangeStrategyUnitRepository parkingChangeStrategyUnitRepository;
    private final KwtParkingStrategySwitchRepository parkingStrategySwitchRepository;

    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 6000)
   RemoteSystemService remoteSystemService;

    private static final BigDecimal ZERO_AMOUNT = BigDecimal.ZERO;
    private static final int STRATEGY_OPEN = 1;
    /** 钱包明细交易类型：冻结（下单时服务费从可用余额转入履约中） */
    private static final int TRADE_TYPE_FREEZE = 4;
    /** 钱包明细交易类型：解冻（审核拒绝全额返还，或订单完结释放履约中金额） */
    private static final int TRADE_TYPE_UNFREEZE = 5;
    /** 钱包明细交易类型：消费（订单完结按实际履约量正式扣减服务费） */
    private static final int TRADE_TYPE_CONSUME = 6;

    /**
     * 查询汇总服务费
     * @param param
     */
    public ParkingWalletFeeResp queryTotalServerFee(ParkingWalletFeeTotalQueryParam param) {
        log.info("查询汇总服务费：{}", JSON.toJSONString(param));
        if (param.getSupEntId() != null) {
            param.setSupEntId(551429255406292993L);
        }

        //构建查询条件
        LambdaQueryWrapper<KwtParkingWalletFee> wrapper = buildAndExecuteQuery(param);

        // 初始化
        ParkingWalletFeeResp resp = new ParkingWalletFeeResp();
        resp.setServiceFeeBalance(BigDecimal.ZERO);
        resp.setTradingAmount(BigDecimal.ZERO);

        List<KwtParkingWalletFee> records = parkingWalletFeeRepository.list(wrapper);
        if (CollectionUtils.isEmpty(records)) {
            log.info("汇总服务费信息为空");
            return resp;
        }
        // 查询采购商汇总服务费
        if (param.getProEntId() != null) {
            return getProWalletFee(records.get(0));
        }
        // 查询平台汇总服务费
        if (param.getSupEntId() != null) {
            return getSupWalletFee(records);
        }
        return resp;
    }

    /**
     * 构建查询条件并执行分页查询
     */
    private LambdaQueryWrapper<KwtParkingWalletFee> buildAndExecuteQuery(ParkingWalletFeeTotalQueryParam param) {
        return  Wrappers.<KwtParkingWalletFee>lambdaQuery()
                .eq(param.getProEntId() != null, KwtParkingWalletFee::getProEntId, param.getProEntId())
                .eq(param.getSupEntId() != null, KwtParkingWalletFee::getSupEntId, param.getSupEntId())
                .orderByDesc(KwtParkingWalletFee::getUpdateTime);
    }

    /**
     * 获取采购商汇总服务费
     * @param fee
     */
    private ParkingWalletFeeResp getProWalletFee(KwtParkingWalletFee fee) {
        log.info("开始汇总采购商服务费，param:{}", JSON.toJSONString(fee));

        ParkingWalletFeeResp resp = new ParkingWalletFeeResp();
        resp.setServiceFeeBalance(fee.getServiceFeeBalance() != null ? fee.getServiceFeeBalance() : BigDecimal.ZERO);
        resp.setTradingAmount(fee.getTradingAmount() != null ? fee.getTradingAmount() : BigDecimal.ZERO);
        resp.setProEntName(getEntName(fee.getProEntId()));
        log.info("汇总采购商服务费结束，总余额:{}, 总履约中金额:{}", fee.getServiceFeeBalance(), fee.getTradingAmount());
        return resp;

    }

    /**
     * 获取平台汇总服务费
     * @param feeList
     */
    private ParkingWalletFeeResp getSupWalletFee(List<KwtParkingWalletFee> feeList) {
        log.info("开始汇总平台服务费， size:{}", CollectionUtils.isEmpty(feeList) ? 0 : feeList.size());
        // 汇总余额
        BigDecimal totalServiceFee  = feeList.stream()
                .map(fee -> fee.getServiceFeeBalance() != null ? fee.getServiceFeeBalance() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // 汇总冻结金额
        BigDecimal totalTradingAmount   = feeList.stream()
                .map(fee -> fee.getTradingAmount() != null ? fee.getTradingAmount() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        ParkingWalletFeeResp resp = new ParkingWalletFeeResp();
        resp.setServiceFeeBalance(totalServiceFee);
        resp.setTradingAmount(totalTradingAmount);
        resp.setSupEntName(getEntName(feeList.get(0).getSupEntId()));
        log.info("汇总平台服务费结束，总余额:{}, 总履约中金额:{}", totalServiceFee, totalTradingAmount);
        return resp;
    }


    /**
     * 分页查询服务费
     * @param param
     */
    public PageDataResult<ParkingWalletFeeResp> pageQueryServerFee(ParkingWalletFeeQueryParam param) {
        log.info("分页查询服务费：{}", JSON.toJSONString(param));
        if (param.getSupEntId() != null) {
            param.setSupEntId(551429255406292993L);
        }

        //构建查询条件
        LambdaQueryWrapper<KwtParkingWalletFee> wrapper = buildAndExecuteQuery(param);

        Page<KwtParkingWalletFee> pageByStatus = parkingWalletFeeRepository.page(new Page<>(param.getPageNum(), param.getPageSize()), wrapper);
        List<KwtParkingWalletFee> records = pageByStatus.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            log.info("服务费信息为空");
            return PageDataResult.empty(param.getPageNum(), param.getPageSize());
        }
        List<ParkingWalletFeeResp> changeStrategyRespList = getWalletFeePageResult(records);
        return PageDataResult.success(param.getPageNum(), param.getPageSize(), pageByStatus.getTotal(), changeStrategyRespList);
    }


    /**
     * 构建查询条件并执行分页查询
     */
    private LambdaQueryWrapper<KwtParkingWalletFee> buildAndExecuteQuery(ParkingWalletFeeQueryParam param) {
        return  Wrappers.<KwtParkingWalletFee>lambdaQuery()
                .eq(param.getSupEntId() != null, KwtParkingWalletFee::getSupEntId, param.getSupEntId())
                .eq(param.getProEntId() != null, KwtParkingWalletFee::getProEntId, param.getProEntId())
                .ge(param.getMinFee() != null, KwtParkingWalletFee::getServiceFeeBalance, param.getMinFee())
                .le(param.getMaxFee() != null, KwtParkingWalletFee::getServiceFeeBalance, param.getMaxFee())
                .orderByDesc(KwtParkingWalletFee::getUpdateTime);
    }

    /**
     * 获取收费策略
     * @param records
     */
    private List<ParkingWalletFeeResp> getWalletFeePageResult(List<KwtParkingWalletFee> records) {
        log.info("组装服务费，param:{}", JSON.toJSONString(records));
        if (CollectionUtils.isEmpty(records)) {
            return Collections.emptyList();
        }
        List<ParkingWalletFeeResp> walletFeeList = records.stream()
                .map(fee -> {
                    ParkingWalletFeeResp resp = new ParkingWalletFeeResp();
                    resp.setId(fee.getId());
                    resp.setProEntId(fee.getProEntId());
                    resp.setProEntName(getEntName(fee.getProEntId()));
                    resp.setSupEntId(fee.getSupEntId());
                    resp.setSupEntName(getEntName(fee.getSupEntId()));
                    resp.setServiceFeeBalance(fee.getServiceFeeBalance());
                    resp.setTradingAmount(fee.getTradingAmount());
                    resp.setUpdateTime(fee.getUpdateTime());
                    return resp;
                }).collect(Collectors.toList());

        log.info("组装服务费结束，size:{}", JSON.toJSONString(walletFeeList.size()));
        return walletFeeList;
    }


    /**
     * 保存服务费
     * @param param
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveServerFee(ParkingWalletFeeSaveParam param) {
        log.info("保存服务费，param：{}", JSON.toJSONString(param));
        if (param.getSupEntId() != null) {
            param.setSupEntId(551429255406292993L);
        }

        KwtParkingWalletFee walletFee = parkingWalletFeeRepository.getById(param.getId());
        if (walletFee == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "服务费信息不存在");
        }

        // 预付
        if (Objects.equals(param.getPaymentType(), 1)) {
            walletFee.setServiceFeeBalance(walletFee.getServiceFeeBalance().add(param.getServiceFee()));
        }else {
            if (walletFee.getServiceFeeBalance().compareTo(param.getServiceFee()) < 0) {
                throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "扣款金额不能大于服务余额");
            }
            walletFee.setServiceFeeBalance(walletFee.getServiceFeeBalance().subtract(param.getServiceFee()));
        }

        // 1. 先修改服务余额
        parkingWalletFeeRepository.updateById(walletFee);

        // 2.新增明细
        KwtParkingWalletFeeBalance feeBalance = new KwtParkingWalletFeeBalance();
        feeBalance.setSupEntId(param.getSupEntId());
        feeBalance.setProEntId(param.getProEntId());
        feeBalance.setTradeType(9);
        feeBalance.setPaymentType(param.getPaymentType());
        feeBalance.setTradeAmount(param.getServiceFee());
        feeBalance.setServiceFeeBalance(walletFee.getServiceFeeBalance());
        feeBalance.setTradingAmount(walletFee.getTradingAmount());
        feeBalance.setVoucherUrl(param.getVoucherUrl());
        feeBalance.setRemark(param.getRemark());
        parkingWalletFeeBalanceRepository.save(feeBalance);
    }

    /**
     * 分页查询服务费明细
     * @param param
     */
    public PageDataResult<ParkingWalletFeeBalanceResp> pageQueryServerFeeDetails(ParkingWalletFeeBalanceQueryParam param) {
        log.info("分页查询服务费明细：{}", JSON.toJSONString(param));
        if (param.getSupEntId() != null) {
            param.setSupEntId(551429255406292993L);
        }
        //构建查询条件
        LambdaQueryWrapper<KwtParkingWalletFeeBalance> wrapper = buildAndExecuteQuery(param);

        Page<KwtParkingWalletFeeBalance> pageByStatus = parkingWalletFeeBalanceRepository.page(new Page<>(param.getPageNum(), param.getPageSize()), wrapper);
        List<KwtParkingWalletFeeBalance> records = pageByStatus.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            log.info("分页查询服务费明细为空");
            return PageDataResult.empty(param.getPageNum(), param.getPageSize());
        }
        List<ParkingWalletFeeBalanceResp> changeStrategyRespList = getWalletFeeBalancePageResult(records);
        return PageDataResult.success(param.getPageNum(), param.getPageSize(), pageByStatus.getTotal(), changeStrategyRespList);
    }


    /**
     * 构建查询条件并执行分页查询
     */
    private LambdaQueryWrapper<KwtParkingWalletFeeBalance> buildAndExecuteQuery(ParkingWalletFeeBalanceQueryParam param) {
        return  Wrappers.<KwtParkingWalletFeeBalance>lambdaQuery()
                .eq(param.getSupEntId() != null, KwtParkingWalletFeeBalance::getSupEntId, param.getSupEntId())
                .eq(param.getProEntId() != null, KwtParkingWalletFeeBalance::getProEntId, param.getProEntId())
                .eq(StringUtils.isNotBlank(param.getOrderNo()), KwtParkingWalletFeeBalance::getOrderNo, param.getOrderNo())
                .eq(param.getTradeType() != null,KwtParkingWalletFeeBalance::getTradeType, param.getTradeType())
                .ge(param.getMinFee() != null, KwtParkingWalletFeeBalance::getTradeAmount, param.getMinFee())
                .le(param.getMaxFee() != null, KwtParkingWalletFeeBalance::getTradeAmount, param.getMaxFee())
                .ge(param.getStartCreateTime() != null, KwtParkingWalletFeeBalance::getCreateTime, param.getStartCreateTime())
                .le(param.getEndCreateTime() != null, KwtParkingWalletFeeBalance::getCreateTime, param.getEndCreateTime())
                .orderByDesc(KwtParkingWalletFeeBalance::getCreateTime)
                .orderByDesc(KwtParkingWalletFeeBalance::getId);
    }

    /**
     * 获取服务费明细
     * @param records
     */
    private List<ParkingWalletFeeBalanceResp> getWalletFeeBalancePageResult(List<KwtParkingWalletFeeBalance> records) {
        log.info("组装服务费明细，param:{}", JSON.toJSONString(records));
        if (CollectionUtils.isEmpty(records)) {
            return Collections.emptyList();
        }
        List<ParkingWalletFeeBalanceResp> walletFeeList = records.stream()
                .map(feeBalance -> {
                    ParkingWalletFeeBalanceResp resp = new ParkingWalletFeeBalanceResp();
                    resp.setId(feeBalance.getId());
                    resp.setOrderNo(Objects.equals(feeBalance.getOrderNo(), "-1") ? null : feeBalance.getOrderNo());
                    resp.setProEntId(feeBalance.getProEntId());
                    resp.setProEntName(getEntName(feeBalance.getProEntId()));
                    resp.setSupEntId(feeBalance.getSupEntId());
                    resp.setSupEntName(getEntName(feeBalance.getSupEntId()));
                    resp.setTradeType(feeBalance.getTradeType());
                    resp.setTradeTypeDesc(WalletTypEnum.getDescByCode(feeBalance.getTradeType()));
                    resp.setPaymentType(feeBalance.getPaymentType());
                    // 人人工录入
                    if (Objects.equals(feeBalance.getTradeType(), WalletTypEnum.MANUAL_ENTRY.getCode())) {
                        resp.setTradeAmount(Objects.equals(feeBalance.getPaymentType(), 1) ? feeBalance.getTradeAmount() : feeBalance.getTradeAmount().negate());
                    } else if (Objects.equals(feeBalance.getTradeType(), WalletTypEnum.FREEZE.getCode()) ||
                            Objects.equals(feeBalance.getTradeType(), WalletTypEnum.CONSUME.getCode())){
                        resp.setTradeAmount(feeBalance.getTradeAmount().negate());
                    } else {
                        resp.setTradeAmount(feeBalance.getTradeAmount());
                    }

                    resp.setServiceFeeBalance(feeBalance.getServiceFeeBalance());
                    resp.setTradingAmount(feeBalance.getTradingAmount());
                    resp.setVoucherUrl(feeBalance.getVoucherUrl());
                    resp.setRemark(feeBalance.getRemark());
                    resp.setCreateTime(feeBalance.getCreateTime());
                    return resp;
                }).collect(Collectors.toList());

        log.info("组装服务费明细结束，size:{}", JSON.toJSONString(walletFeeList.size()));
        return walletFeeList;
    }

    /**
     * 通过企业id查询企业名称
     * @param entId
     */
    private String getEntName(Long entId) {
        // 查询企业名称
        EntCacheResDto entCacheResDto = remoteSystemService.queryEntDetails(entId);
        if (entCacheResDto == null) {
            return null;
        }
        return entCacheResDto.getFirmName();
    }

    /**
     * 查询服务费余额、本次预计服务费与最大可购买数量。
     * <p>
     * 业务规则：
     * 1. 服务费余额取当前登录采购企业的可用服务费余额；
     * 2. 收费策略总开关关闭时，不计算预计服务费，最大可购买数量返回 null，表示不做余额约束；
     * 3. 收费策略总开关开启时，按企业绑定的当前收费策略计算预计服务费；无企业策略时使用开关表 default_fee；
     * 4. 策略 method 为 0.00 时，实际单价使用 kwt_parking_strategy_switch.default_fee；
     * 5. 最大可购买数量 = 服务费余额 / 实际策略单价，向下取整，避免超出余额。
     *
     * @param param 服务费预估查询参数，purchaseQuantity 为本次采购数量
     * @return 服务费余额、本次预计服务费与最大可购买数量
     */
    public ParkingWalletFeeEstimateResp queryEstimateServiceFee(ParkingWalletFeeEstimateQueryParam param) {
        Long entId = LoginUserHolder.getEntId();
        log.info("服务费预估开始，企业id:{}, 查询参数:{}", entId, param);
        if (param == null) {
            log.warn("服务费预估参数为空，企业id:{}", entId);
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "服务费预估参数不能为空");
        }
        if (param.getPurchaseQuantity() == null || param.getPurchaseQuantity().compareTo(ZERO_AMOUNT) < 0) {
            log.warn("服务费预估参数异常，采购数量不能为空且不能小于0，企业id:{}, 采购数量:{}",
                    entId, param.getPurchaseQuantity());
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "采购数量不能为空且不能小于0");
        }

        // 查询采购企业当前可用服务费余额；supEntId 为空时按采购企业汇总口径取最新钱包记录。
        BigDecimal serviceFeeBalance = queryServiceFeeBalance(entId, null);
        log.info("服务费预估余额查询完成，企业id:{}, 服务费余额:{}", entId, serviceFeeBalance);

        // 收费策略总开关统一以 kwt_parking_strategy_switch.status 为准，策略表 status 不再作为计费开关。
        boolean chargeStrategySwitchOpen = isChargeStrategySwitchOpen();

        // 查询当前企业绑定的最新收费策略；无企业策略或 method 为 0.00 时，resolveStrategyUnitFee 会使用开关表 default_fee。
        KwtParkingChargeStrategy currentStrategy = queryCurrentEnableStrategy(entId);
        BigDecimal currentStrategyUnitFee = resolveStrategyUnitFee(currentStrategy);
        log.info("服务费预估策略匹配完成，企业id:{}, 开关状态:{}, 策略id:{}, 策略原始单价:{}, 实际计费单价:{}",
                entId,
                chargeStrategySwitchOpen ? "开启" : "关闭",
                currentStrategy == null ? null : currentStrategy.getId(),
                currentStrategy == null ? null : currentStrategy.getMethod(),
                currentStrategyUnitFee);

        // 本次预计服务费 = 采购数量 * 实际计费单价，金额保留2位小数；开关关闭时固定返回0。
        BigDecimal estimatedServiceFee = chargeStrategySwitchOpen
                ? param.getPurchaseQuantity().multiply(currentStrategyUnitFee).setScale(2, RoundingMode.HALF_UP)
                : ZERO_AMOUNT;
        log.info("服务费预估金额计算完成，企业id:{}, 采购数量:{}, 实际计费单价:{}, 预计服务费:{}",
                entId, param.getPurchaseQuantity(), currentStrategyUnitFee, estimatedServiceFee);

        // 开关开启且存在有效单价时，按服务费余额计算最大可购买数量；否则返回 null。
        BigDecimal maxPurchaseQuantity = calculateMaxPurchaseQuantity(currentStrategyUnitFee, serviceFeeBalance);
        log.info("服务费预估计算完成，企业id:{}, 采购数量:{}, 服务费余额:{}, 预计服务费:{}, 最大可购买数量:{}",
                entId, param.getPurchaseQuantity(), serviceFeeBalance, estimatedServiceFee, maxPurchaseQuantity);

        ParkingWalletFeeEstimateResp resp = new ParkingWalletFeeEstimateResp();
        resp.setServiceFeeBalance(serviceFeeBalance);
        resp.setEstimatedServiceFee(estimatedServiceFee);
        resp.setMaxPurchaseQuantity(maxPurchaseQuantity);
        log.info("服务费预估结束，企业id:{}, 响应结果:{}", entId, resp);
        return resp;
    }


    /**
     * 贸易订单下单应用收费策略并冻结服务费
     * 规则：
     * 1. 收费策略开关未开启时，不冻结服务费，订单记录为未应用收费策略
     * 2. 收费策略开关开启时，冻结金额=采购数量*策略单价，并记录策略信息
     *
     * @param param 冻结参数
     * @return 收费策略应用结果
     */
    @Transactional(rollbackFor = Exception.class)
    public ParkingWalletFeeFreezeResult applyChargeStrategyFreeze(ParkingWalletFeeFreezeParam param) {
        log.info("贸易订单应用收费策略开始，param:{}", param);
        if (param == null || param.getProEntId() == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "采购方企业id不能为空");
        }
        if (param.getPurchaseQuantity() == null || param.getPurchaseQuantity().compareTo(ZERO_AMOUNT) < 0) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "采购数量不能为空且不能小于0");
        }
        if (param.getOrderNo() == null || param.getOrderNo().isBlank()) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "贸易订单号不能为空");
        }

        ParkingWalletFeeFreezeResult result = new ParkingWalletFeeFreezeResult();
        result.setApplyChargeStrategy(Global.NO);
        result.setFreezeAmount(ZERO_AMOUNT);

        if (!isChargeStrategySwitchOpen()) {
            log.info("收费策略开关未开启，跳过服务费冻结，proEntId:{}, orderNo:{}",
                    param.getProEntId(), param.getOrderNo());
            return result;
        }

        KwtParkingChargeStrategy currentStrategy = queryCurrentEnableStrategy(param.getProEntId());
        if (currentStrategy == null) {
            log.info("未匹配到收费策略，跳过服务费冻结，proEntId:{}, orderNo:{}",
                    param.getProEntId(), param.getOrderNo());
            return result;
        }

        BigDecimal unitFee = resolveStrategyUnitFee(currentStrategy);
        if (unitFee.compareTo(ZERO_AMOUNT) <= 0) {
            log.info("收费策略单价无效，跳过服务费冻结，strategyId:{}, unitFee:{}",
                    currentStrategy.getId(), unitFee);
            return result;
        }

        BigDecimal freezeAmount = param.getPurchaseQuantity().multiply(unitFee).setScale(2, RoundingMode.HALF_UP);
        KwtParkingWalletFee walletFee = queryWalletFee(param.getProEntId(), param.getSupEntId());
        if (walletFee == null) {
            log.warn("服务费账户不存在，proEntId:{}, supEntId:{}, orderNo:{}",
                    param.getProEntId(), param.getSupEntId(), param.getOrderNo());
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "采购方服务费账户不存在");
        }

        BigDecimal currentBalance = walletFee.getServiceFeeBalance() == null ? ZERO_AMOUNT : walletFee.getServiceFeeBalance();
        if (currentBalance.compareTo(freezeAmount) < 0) {
            log.warn("服务费余额不足，proEntId:{}, orderNo:{}, balance:{}, freezeAmount:{}",
                    param.getProEntId(), param.getOrderNo(), currentBalance, freezeAmount);
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "服务费余额不足，无法下单");
        }

        BigDecimal currentTradingAmount = walletFee.getTradingAmount() == null ? ZERO_AMOUNT : walletFee.getTradingAmount();
        walletFee.setServiceFeeBalance(currentBalance.subtract(freezeAmount));
        walletFee.setTradingAmount(currentTradingAmount.add(freezeAmount));
        parkingWalletFeeRepository.updateById(walletFee);

        saveFreezeWalletBalanceLog(param, walletFee, freezeAmount);

        result.setApplyChargeStrategy(Global.YES);
        result.setChargeStrategyId(currentStrategy.getId());
        result.setChargeStrategyDesc(buildStrategyMethodDesc(currentStrategy));
        result.setChargeStrategyAmount(unitFee);
        result.setFreezeAmount(freezeAmount);
        result.setServiceFeeBalance(walletFee.getServiceFeeBalance());
        log.info("贸易订单应用收费策略完成，orderNo:{}, result:{}", param.getOrderNo(), result);
        return result;
    }

    /**
     * 贸易订单审核拒绝解冻服务费
     * 规则：根据订单冻结记录解冻，返还服务费余额并写入钱包日志
     *
     * @param param 解冻参数
     * @return 解冻结果（含采购方服务费余额）
     */
    @Transactional(rollbackFor = Exception.class)
    public ParkingWalletFeeFreezeResult unfreezeChargeStrategy(ParkingWalletFeeFreezeParam param) {
        log.info("贸易订单解冻服务费开始，param:{}", param);
        validateUnfreezeParam(param);

        ParkingWalletFeeFreezeResult result = new ParkingWalletFeeFreezeResult();
        result.setApplyChargeStrategy(Global.YES);

        if (existsUnfreezeRecord(param.getOrderNo(), param.getProEntId(), param.getSupEntId())) {
            log.info("服务费已解冻，跳过重复处理，orderNo:{}, proEntId:{}", param.getOrderNo(), param.getProEntId());
            result.setServiceFeeBalance(queryServiceFeeBalance(param.getProEntId(), param.getSupEntId()));
            return result;
        }

        KwtParkingWalletFeeBalance freezeRecord = queryFreezeBalanceRecord(param);
        if (freezeRecord == null) {
            log.warn("未找到服务费冻结记录，orderNo:{}, proEntId:{}", param.getOrderNo(), param.getProEntId());
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "服务费冻结记录不存在，无法解冻");
        }

        BigDecimal unfreezeAmount = freezeRecord.getTradeAmount() == null ? ZERO_AMOUNT : freezeRecord.getTradeAmount();
        if (unfreezeAmount.compareTo(ZERO_AMOUNT) <= 0) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "服务费冻结金额异常，无法解冻");
        }

        KwtParkingWalletFee walletFee = queryWalletFee(param.getProEntId(), param.getSupEntId());
        if (walletFee == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "采购方服务费账户不存在");
        }

        BigDecimal currentTradingAmount = walletFee.getTradingAmount() == null ? ZERO_AMOUNT : walletFee.getTradingAmount();
        if (currentTradingAmount.compareTo(unfreezeAmount) < 0) {
            log.warn("服务费履约中金额不足，无法解冻，orderNo:{}, tradingAmount:{}, unfreezeAmount:{}",
                    param.getOrderNo(), currentTradingAmount, unfreezeAmount);
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "服务费履约中金额不足，无法解冻");
        }

        BigDecimal currentBalance = walletFee.getServiceFeeBalance() == null ? ZERO_AMOUNT : walletFee.getServiceFeeBalance();
        walletFee.setServiceFeeBalance(currentBalance.add(unfreezeAmount));
        walletFee.setTradingAmount(currentTradingAmount.subtract(unfreezeAmount));
        parkingWalletFeeRepository.updateById(walletFee);

        saveUnfreezeWalletBalanceLog(param, walletFee, unfreezeAmount);
        result.setFreezeAmount(unfreezeAmount);
        result.setServiceFeeBalance(walletFee.getServiceFeeBalance());
        log.info("贸易订单解冻服务费完成，orderNo:{}, unfreezeAmount:{}, balanceAfter:{}",
                param.getOrderNo(), unfreezeAmount, walletFee.getServiceFeeBalance());
        return result;
    }


    /**
     * 贸易订单完结结算服务费
     * <p>
     * 适用场景：所有运单完成后，订单已应用收费策略（applyChargeStrategy=1）。
     * 处理流程与预付钱包完结一致，分两步完成资金流转：
     * <ol>
     *   <li>解冻：将下单时冻结的履约中金额（trading_amount）释放回可用余额（service_fee_balance），
     *       并写入 trade_type=5 的解冻明细（备注：订单完结解冻服务费）</li>
     *   <li>扣减：按「运输净重量 × 采购方当前最优收费策略单价」从可用余额中正式扣减服务费，
     *       并写入 trade_type=6 的消费明细（备注含策略名称、单价描述、净重量）</li>
     * </ol>
     * 幂等：以 trade_type=6 的消费记录作为结算完成标识，重复调用直接返回当前余额。
     * <p>
     * 钱包状态变化示例（冻结50元，实际扣减40元）：
     * 解冻前 balance=50, trading=50 → 解冻后 balance=100, trading=0 → 扣减后 balance=60, trading=0
     *
     * @param param 结算参数，需包含 orderNo、proEntId、actualQuantity（运输净重量）
     * @return 结算结果，含实际扣减金额（freezeAmount字段）及扣减后服务费余额
     */
    @Transactional(rollbackFor = Exception.class)
    public ParkingWalletFeeFreezeResult settleChargeStrategy(ParkingWalletFeeFreezeParam param) {
        log.info("贸易订单完结结算服务费开始，orderNo:{}, proEntId:{}, supEntId:{}, actualQuantity:{}, chargeStrategyId:{}",
                param.getOrderNo(), param.getProEntId(), param.getSupEntId(),
                param.getActualQuantity(), param.getChargeStrategyId());
        validateSettleParam(param);

        ParkingWalletFeeFreezeResult result = new ParkingWalletFeeFreezeResult();
        result.setApplyChargeStrategy(Global.YES);

        // 幂等校验：已存在消费明细则视为结算完成，避免重复扣减
        if (existsConsumeRecord(param.getOrderNo(), param.getProEntId(), param.getSupEntId())) {
            BigDecimal currentBalance = queryServiceFeeBalance(param.getProEntId(), param.getSupEntId());
            log.info("服务费已结算，跳过重复处理，orderNo:{}, proEntId:{}, currentBalance:{}",
                    param.getOrderNo(), param.getProEntId(), currentBalance);
            result.setServiceFeeBalance(currentBalance);
            return result;
        }

        // 查询下单时的冻结明细，作为解冻金额依据
        KwtParkingWalletFeeBalance freezeRecord = queryFreezeBalanceRecord(param);
        if (freezeRecord == null) {
            log.warn("未找到服务费冻结记录，无法结算，orderNo:{}, proEntId:{}, supEntId:{}",
                    param.getOrderNo(), param.getProEntId(), param.getSupEntId());
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "服务费冻结记录不存在，无法结算");
        }

        BigDecimal freezeAmount = freezeRecord.getTradeAmount() == null ? ZERO_AMOUNT : freezeRecord.getTradeAmount();
        if (freezeAmount.compareTo(ZERO_AMOUNT) <= 0) {
            log.warn("服务费冻结金额异常，无法结算，orderNo:{}, freezeRecordId:{}, freezeAmount:{}",
                    param.getOrderNo(), freezeRecord.getId(), freezeAmount);
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "服务费冻结金额异常，无法结算");
        }
        log.info("查询到服务费冻结记录，orderNo:{}, freezeRecordId:{}, freezeAmount:{}",
                param.getOrderNo(), freezeRecord.getId(), freezeAmount);

        KwtParkingWalletFee walletFee = queryWalletFee(param.getProEntId(), param.getSupEntId());
        if (walletFee == null) {
            log.warn("采购方服务费账户不存在，无法结算，orderNo:{}, proEntId:{}, supEntId:{}",
                    param.getOrderNo(), param.getProEntId(), param.getSupEntId());
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "采购方服务费账户不存在");
        }

        BigDecimal balanceBeforeSettle = walletFee.getServiceFeeBalance() == null ? ZERO_AMOUNT : walletFee.getServiceFeeBalance();
        BigDecimal tradingBeforeSettle = walletFee.getTradingAmount() == null ? ZERO_AMOUNT : walletFee.getTradingAmount();
        log.info("结算前钱包状态，orderNo:{}, walletFeeId:{}, balance:{}, tradingAmount:{}",
                param.getOrderNo(), walletFee.getId(), balanceBeforeSettle, tradingBeforeSettle);

        // 第一步：解冻履约中金额，释放回可用余额（与预付钱包完结解冻逻辑一致）
        if (tradingBeforeSettle.compareTo(freezeAmount) < 0) {
            log.warn("服务费履约中金额不足，无法结算，orderNo:{}, tradingAmount:{}, freezeAmount:{}",
                    param.getOrderNo(), tradingBeforeSettle, freezeAmount);
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "服务费履约中金额不足，无法结算");
        }
        walletFee.setServiceFeeBalance(balanceBeforeSettle.add(freezeAmount));
        walletFee.setTradingAmount(tradingBeforeSettle.subtract(freezeAmount));
        log.info("完结解冻完成（内存态），orderNo:{}, unfreezeAmount:{}, balanceAfterUnfreeze:{}, tradingAfterUnfreeze:{}",
                param.getOrderNo(), freezeAmount, walletFee.getServiceFeeBalance(), walletFee.getTradingAmount());

        // 第二步：运输净重量 × 采购方当前最优收费策略单价 = 本次实际扣减服务费
        SettleConsumeInfo consumeInfo = resolveSettleConsumeInfo(param, freezeAmount);
        BigDecimal consumeAmount = consumeInfo.consumeAmount();
        if (consumeAmount.compareTo(ZERO_AMOUNT) < 0) {
            log.warn("服务费扣减金额计算异常，orderNo:{}, consumeAmount:{}", param.getOrderNo(), consumeAmount);
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "服务费扣减金额异常，无法结算");
        }
        log.info("服务费扣减金额计算完成，orderNo:{}, transportNetWeight:{}, strategyId:{}, strategyName:{}, strategyDesc:{}, freezeAmount:{}, consumeAmount:{}",
                param.getOrderNo(), consumeInfo.transportNetWeight(), consumeInfo.strategyId(),
                consumeInfo.strategyName(), consumeInfo.strategyDesc(), freezeAmount, consumeAmount);

        saveSettleUnfreezeWalletBalanceLog(param, walletFee, freezeAmount, consumeInfo);

        BigDecimal balanceAfterUnfreeze = walletFee.getServiceFeeBalance();
        if (balanceAfterUnfreeze.compareTo(consumeAmount) < 0) {
            log.warn("服务费余额不足，无法扣减，orderNo:{}, balanceAfterUnfreeze:{}, consumeAmount:{}",
                    param.getOrderNo(), balanceAfterUnfreeze, consumeAmount);
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "服务费余额不足，无法结算扣减");
        }
        walletFee.setServiceFeeBalance(balanceAfterUnfreeze.subtract(consumeAmount));
        parkingWalletFeeRepository.updateById(walletFee);

        saveConsumeWalletBalanceLog(param, walletFee, consumeInfo);
        result.setChargeStrategyId(consumeInfo.strategyId());
        result.setChargeStrategyDesc(consumeInfo.strategyDesc());
        result.setFreezeAmount(consumeAmount);
        result.setServiceFeeBalance(walletFee.getServiceFeeBalance());
        log.info("贸易订单完结结算服务费完成，orderNo:{}, freezeAmount:{}, consumeAmount:{}, strategyDesc:{}, balanceBeforeSettle:{}, balanceAfterSettle:{}, tradingBeforeSettle:{}, tradingAfterSettle:{}",
                param.getOrderNo(), freezeAmount, consumeAmount, consumeInfo.strategyDesc(),
                balanceBeforeSettle, walletFee.getServiceFeeBalance(), tradingBeforeSettle, walletFee.getTradingAmount());
        return result;
    }

    /**
     * 订单完结服务费扣减计算结果
     *
     * @param consumeAmount     本次实际扣减服务费
     * @param transportNetWeight 运输净重量
     * @param strategyId        采用的收费策略id
     * @param strategyName      采用的收费策略名称
     * @param strategyDesc      收费策略单价描述，如10元/吨
     */
    private record SettleConsumeInfo(BigDecimal consumeAmount,
                                     BigDecimal transportNetWeight,
                                     Long strategyId,
                                     String strategyName,
                                     String strategyDesc) {
    }


    /**
     * 查询采购方服务费余额
     */
    public BigDecimal queryPurchaserServiceFeeBalance(Long proEntId, Long supEntId) {
        return queryServiceFeeBalance(proEntId, supEntId);
    }

    private void validateUnfreezeParam(ParkingWalletFeeFreezeParam param) {
        if (param == null || param.getProEntId() == null) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "采购方企业id不能为空");
        }
        if (param.getOrderNo() == null || param.getOrderNo().isBlank()) {
            throw new BusinessPlatfromException(ErrorCodeEnum.PARAM_ERROR, "贸易订单号不能为空");
        }
    }

    /**
     * 校验订单完结结算入参（订单号、采购方企业id必填）
     */
    private void validateSettleParam(ParkingWalletFeeFreezeParam param) {
        validateUnfreezeParam(param);
    }

    /**
     * 判断订单是否已完成服务费结算（存在 trade_type=6 的消费明细即为已结算）
     */
    private boolean existsConsumeRecord(String orderNo, Long proEntId, Long supEntId) {
        return parkingWalletFeeBalanceRepository.count(
                Wrappers.<KwtParkingWalletFeeBalance>lambdaQuery()
                        .eq(KwtParkingWalletFeeBalance::getOrderNo, orderNo)
                        .eq(KwtParkingWalletFeeBalance::getProEntId, proEntId)
                        .eq(supEntId != null, KwtParkingWalletFeeBalance::getSupEntId, supEntId)
                        .eq(KwtParkingWalletFeeBalance::getTradeType, TRADE_TYPE_CONSUME)
                        .eq(KwtParkingWalletFeeBalance::getDelFlag, Global.NO)
        ) > 0;
    }

    /**
     * 解析订单完结服务费扣减信息
     * <p>
     * 扣减金额 = 运输净重量 × 收费策略单价；
     * 单价优先取订单下单快照（chargeStrategyAmount），无快照时再取采购方当前最优策略；
     * 若无法匹配策略，则回退为下单冻结金额。
     *
     * @param param        结算参数（actualQuantity 为运输净重量）
     * @param freezeAmount 下单冻结金额（兜底扣减值）
     * @return 扣减计算结果
     */
    private SettleConsumeInfo resolveSettleConsumeInfo(ParkingWalletFeeFreezeParam param, BigDecimal freezeAmount) {
        BigDecimal transportNetWeight = param.getActualQuantity() == null ? ZERO_AMOUNT : param.getActualQuantity();

        // 优先使用订单下单时快照的收费策略单价，避免策略表变更后扣减金额变化
        BigDecimal snapshotUnitFee = param.getChargeStrategyAmount();
        if (snapshotUnitFee != null && snapshotUnitFee.compareTo(ZERO_AMOUNT) > 0) {
            BigDecimal consumeAmount = transportNetWeight.multiply(snapshotUnitFee).setScale(2, RoundingMode.HALF_UP);
            log.info("按订单快照单价计算扣减，orderNo:{}, transportNetWeight:{}, snapshotUnitFee:{}, consumeAmount:{}",
                    param.getOrderNo(), transportNetWeight, snapshotUnitFee, consumeAmount);
            return new SettleConsumeInfo(consumeAmount, transportNetWeight, param.getChargeStrategyId(),
                    null, buildSnapshotStrategyDesc(snapshotUnitFee));
        }

        KwtParkingChargeStrategy strategy = queryOptimalEnableStrategy(param.getProEntId());
        if (strategy == null && param.getChargeStrategyId() != null) {
            strategy = parkingChangeStrategyRepository.getById(param.getChargeStrategyId());
            log.info("未匹配到当前最优策略，回退使用订单关联策略，orderNo:{}, chargeStrategyId:{}",
                    param.getOrderNo(), param.getChargeStrategyId());
        }
        if (strategy == null) {
            log.warn("收费策略无效，扣减金额按冻结金额处理，orderNo:{}, freezeAmount:{}", param.getOrderNo(), freezeAmount);
            return new SettleConsumeInfo(freezeAmount, transportNetWeight, null, null, null);
        }
        BigDecimal unitFee = resolveStrategyUnitFee(strategy);
        if (unitFee.compareTo(ZERO_AMOUNT) <= 0) {
            log.warn("收费策略单价无效，扣减金额按冻结金额处理，orderNo:{}, freezeAmount:{}", param.getOrderNo(), freezeAmount);
            return new SettleConsumeInfo(freezeAmount, transportNetWeight, null, null, null);
        }
        String strategyDesc = buildStrategyMethodDesc(strategy);
        BigDecimal consumeAmount = transportNetWeight.multiply(unitFee).setScale(2, RoundingMode.HALF_UP);
        log.info("按运输净重量×最优策略单价计算扣减，orderNo:{}, transportNetWeight:{}, strategyId:{}, strategyName:{}, unitFee:{}, consumeAmount:{}",
                param.getOrderNo(), transportNetWeight, strategy.getId(), strategy.getStrategyName(),
                unitFee, consumeAmount);
        return new SettleConsumeInfo(consumeAmount, transportNetWeight, strategy.getId(),
                strategy.getStrategyName(), strategyDesc);
    }

    /**
     * 构建完结结算钱包明细备注
     */
    private String buildSettleWalletRemark(String actionDesc, ParkingWalletFeeFreezeParam param, SettleConsumeInfo consumeInfo) {
        StringBuilder remark = new StringBuilder();
        remark.append("订单").append(param.getOrderNo()).append("，").append(actionDesc);
        if (consumeInfo.strategyName() != null) {
            remark.append("，策略：").append(consumeInfo.strategyName());
        }
        if (consumeInfo.strategyDesc() != null) {
            remark.append("，").append(consumeInfo.strategyDesc());
        }
        if (consumeInfo.transportNetWeight() != null) {
            remark.append("，净重").append(consumeInfo.transportNetWeight().stripTrailingZeros().toPlainString());
        }
        return remark.toString();
    }

    private boolean existsUnfreezeRecord(String orderNo, Long proEntId, Long supEntId) {
        return parkingWalletFeeBalanceRepository.count(
                Wrappers.<KwtParkingWalletFeeBalance>lambdaQuery()
                        .eq(KwtParkingWalletFeeBalance::getOrderNo, orderNo)
                        .eq(KwtParkingWalletFeeBalance::getProEntId, proEntId)
                        .eq(supEntId != null, KwtParkingWalletFeeBalance::getSupEntId, supEntId)
                        .eq(KwtParkingWalletFeeBalance::getTradeType, TRADE_TYPE_UNFREEZE)
                        .eq(KwtParkingWalletFeeBalance::getDelFlag, Global.NO)
        ) > 0;
    }

    private KwtParkingWalletFeeBalance queryFreezeBalanceRecord(ParkingWalletFeeFreezeParam param) {
        return parkingWalletFeeBalanceRepository.getOne(
                Wrappers.<KwtParkingWalletFeeBalance>lambdaQuery()
                        .eq(KwtParkingWalletFeeBalance::getOrderNo, param.getOrderNo())
                        .eq(KwtParkingWalletFeeBalance::getProEntId, param.getProEntId())
                        .eq(param.getSupEntId() != null, KwtParkingWalletFeeBalance::getSupEntId, param.getSupEntId())
                        .eq(KwtParkingWalletFeeBalance::getTradeType, TRADE_TYPE_FREEZE)
                        .eq(KwtParkingWalletFeeBalance::getDelFlag, Global.NO)
                        .orderByDesc(KwtParkingWalletFeeBalance::getId)
                        .last("limit 1"),
                false
        );
    }

    private void saveUnfreezeWalletBalanceLog(ParkingWalletFeeFreezeParam param,
                                              KwtParkingWalletFee walletFee,
                                              BigDecimal unfreezeAmount) {
        Long operatorId = resolveOperatorId(param.getOperatorId());
        Date now = new Date();
        KwtParkingWalletFeeBalance balanceRecord = new KwtParkingWalletFeeBalance();
        balanceRecord.setOrderNo(param.getOrderNo());
        balanceRecord.setProEntId(param.getProEntId());
        balanceRecord.setSupEntId(param.getSupEntId());
        balanceRecord.setTradeType(TRADE_TYPE_UNFREEZE);
        balanceRecord.setTradeAmount(unfreezeAmount);
        balanceRecord.setServiceFeeBalance(walletFee.getServiceFeeBalance());
        balanceRecord.setTradingAmount(walletFee.getTradingAmount());
        balanceRecord.setRemark("贸易订单号：" + param.getOrderNo() + "，审核拒绝解冻服务费");
        balanceRecord.setDelFlag(Global.NO);
        balanceRecord.setCreateUser(operatorId);
        balanceRecord.setUpdateUser(operatorId);
        balanceRecord.setCreateTime(now);
        balanceRecord.setUpdateTime(now);
        parkingWalletFeeBalanceRepository.save(balanceRecord);
        log.info("服务费解冻钱包日志已写入kwt_parking_wallet_fee_balance，orderNo:{}, proEntId:{}, supEntId:{}, tradeType:{}, tradeAmount:{}, balanceAfter:{}",
                param.getOrderNo(), param.getProEntId(), param.getSupEntId(), TRADE_TYPE_UNFREEZE,
                unfreezeAmount, walletFee.getServiceFeeBalance());
    }
    /**
     * 写入订单完结解冻明细（trade_type=5）
     * 仅释放履约中金额至可用余额，不代表最终扣减完成
     */
    private void saveSettleUnfreezeWalletBalanceLog(ParkingWalletFeeFreezeParam param,
                                                    KwtParkingWalletFee walletFee,
                                                    BigDecimal unfreezeAmount,
                                                    SettleConsumeInfo consumeInfo) {
        Long operatorId = resolveOperatorId(param.getOperatorId());
        Date now = new Date();
        KwtParkingWalletFeeBalance balanceRecord = new KwtParkingWalletFeeBalance();
        balanceRecord.setOrderNo(param.getOrderNo());
        balanceRecord.setProEntId(param.getProEntId());
        balanceRecord.setSupEntId(param.getSupEntId());
        balanceRecord.setTradeType(TRADE_TYPE_UNFREEZE);
        balanceRecord.setTradeAmount(unfreezeAmount);
        balanceRecord.setServiceFeeBalance(walletFee.getServiceFeeBalance());
        balanceRecord.setTradingAmount(walletFee.getTradingAmount());
        balanceRecord.setRemark(buildSettleWalletRemark("完结解冻服务费", param, consumeInfo));
        balanceRecord.setDelFlag(Global.NO);
        balanceRecord.setCreateUser(operatorId);
        balanceRecord.setUpdateUser(operatorId);
        balanceRecord.setCreateTime(now);
        balanceRecord.setUpdateTime(now);
        parkingWalletFeeBalanceRepository.save(balanceRecord);
        log.info("服务费完结解冻明细已写入kwt_parking_wallet_fee_balance，orderNo:{}, remark:{}, tradeAmount:{}, balanceAfter:{}, tradingAfter:{}",
                param.getOrderNo(), balanceRecord.getRemark(), unfreezeAmount,
                walletFee.getServiceFeeBalance(), walletFee.getTradingAmount());
    }


    /**
     * 写入订单完结扣减明细（trade_type=6）
     * 标志服务费正式消费完成，同时作为结算幂等依据
     */
    private void saveConsumeWalletBalanceLog(ParkingWalletFeeFreezeParam param,
                                             KwtParkingWalletFee walletFee,
                                             SettleConsumeInfo consumeInfo) {
        Long operatorId = resolveOperatorId(param.getOperatorId());
        Date now = new Date();
        KwtParkingWalletFeeBalance balanceRecord = new KwtParkingWalletFeeBalance();
        balanceRecord.setOrderNo(param.getOrderNo());
        balanceRecord.setProEntId(param.getProEntId());
        balanceRecord.setSupEntId(param.getSupEntId());
        balanceRecord.setTradeType(TRADE_TYPE_CONSUME);
        balanceRecord.setTradeAmount(consumeInfo.consumeAmount());
        balanceRecord.setServiceFeeBalance(walletFee.getServiceFeeBalance());
        balanceRecord.setTradingAmount(walletFee.getTradingAmount());
        balanceRecord.setRemark(buildSettleWalletRemark("完结扣减服务费", param, consumeInfo));
        balanceRecord.setDelFlag(Global.NO);
        balanceRecord.setCreateUser(operatorId);
        balanceRecord.setUpdateUser(operatorId);
        balanceRecord.setCreateTime(now);
        balanceRecord.setUpdateTime(now);
        parkingWalletFeeBalanceRepository.save(balanceRecord);
        log.info("服务费扣减明细已写入kwt_parking_wallet_fee_balance，orderNo:{}, remark:{}, tradeAmount:{}, balanceAfter:{}, tradingAfter:{}",
                param.getOrderNo(), balanceRecord.getRemark(), consumeInfo.consumeAmount(),
                walletFee.getServiceFeeBalance(), walletFee.getTradingAmount());
    }

    private String buildStrategyMethodDesc(KwtParkingChargeStrategy strategy) {
        if (strategy == null) {
            return null;
        }
        BigDecimal unitFee = resolveStrategyUnitFee(strategy);
        if (unitFee.compareTo(ZERO_AMOUNT) <= 0) {
            return null;
        }
        if (Objects.equals(ParkingChangeStrategyEnum.BY_TON.getCode(), strategy.getType())) {
            return unitFee.stripTrailingZeros().toPlainString() + "元/吨";
        }
        if (Objects.equals(ParkingChangeStrategyEnum.BY_TIME.getCode(), strategy.getType())) {
            return unitFee.stripTrailingZeros().toPlainString() + "元/次";
        }
        return unitFee.stripTrailingZeros().toPlainString() + "元/月";
    }

    private String buildSnapshotStrategyDesc(BigDecimal snapshotUnitFee) {
        if (snapshotUnitFee == null || snapshotUnitFee.compareTo(ZERO_AMOUNT) <= 0) {
            return null;
        }
        return snapshotUnitFee.stripTrailingZeros().toPlainString() + "元";
    }

    /**
     * 写入服务费钱包日志（kwt_parking_wallet_fee_balance）
     */
    private void saveFreezeWalletBalanceLog(ParkingWalletFeeFreezeParam param,
                                            KwtParkingWalletFee walletFee,
                                            BigDecimal freezeAmount) {
        Long operatorId = resolveOperatorId(param.getOperatorId());
        Date now = new Date();
        KwtParkingWalletFeeBalance balanceRecord = new KwtParkingWalletFeeBalance();
        balanceRecord.setOrderNo(param.getOrderNo());
        balanceRecord.setProEntId(param.getProEntId());
        balanceRecord.setSupEntId(param.getSupEntId());
        balanceRecord.setTradeType(TRADE_TYPE_FREEZE);
        balanceRecord.setTradeAmount(freezeAmount);
        balanceRecord.setServiceFeeBalance(walletFee.getServiceFeeBalance());
        balanceRecord.setTradingAmount(walletFee.getTradingAmount());
        balanceRecord.setRemark("贸易订单号：" + param.getOrderNo() + "，下单冻结服务费");
        balanceRecord.setDelFlag(Global.NO);
        balanceRecord.setCreateUser(operatorId);
        balanceRecord.setUpdateUser(operatorId);
        balanceRecord.setCreateTime(now);
        balanceRecord.setUpdateTime(now);
        parkingWalletFeeBalanceRepository.save(balanceRecord);
        log.info("服务费钱包日志已写入kwt_parking_wallet_fee_balance，orderNo:{}, proEntId:{}, supEntId:{}, tradeType:{}, tradeAmount:{}, balanceAfter:{}",
                param.getOrderNo(), param.getProEntId(), param.getSupEntId(), TRADE_TYPE_FREEZE,
                freezeAmount, walletFee.getServiceFeeBalance());
    }

    private KwtParkingWalletFee queryWalletFee(Long proEntId, Long supEntId) {
        return parkingWalletFeeRepository.getOne(
                Wrappers.<KwtParkingWalletFee>lambdaQuery()
                        .eq(KwtParkingWalletFee::getProEntId, proEntId)
                        .eq(supEntId != null, KwtParkingWalletFee::getSupEntId, supEntId)
                        .eq(KwtParkingWalletFee::getDelFlag, Global.NO)
                        .orderByDesc(KwtParkingWalletFee::getId)
                        .last("limit 1"),
                false
        );
    }

    private Long resolveOperatorId(Long operatorId) {
        Long loginUserId = LoginUserHolder.getUserId();
        if (loginUserId != null) {
            return loginUserId;
        }
        return operatorId == null ? -1L : operatorId;
    }

    /**
     * 计算服务费余额支持的最大可购买数量。
     * 仅在收费策略总开关开启且实际单价大于 0 时计算：服务费余额 / 单价（向下取整）。
     *
     * @param currentStrategyUnitFee 实际计费单价（含 default_fee 兜底）
     * @param serviceFeeBalance      服务费余额
     * @return 最大可购买数量；开关未开启或单价无效时返回 null
     */
    private BigDecimal calculateMaxPurchaseQuantity(BigDecimal currentStrategyUnitFee,
                                                    BigDecimal serviceFeeBalance) {
        boolean strategySwitchOpen = isChargeStrategySwitchOpen();
        if (!strategySwitchOpen || currentStrategyUnitFee.compareTo(ZERO_AMOUNT) <= 0) {
            log.info("最大可购买数量未计算，原因:{}",
                    !strategySwitchOpen ? "收费策略开关未开启" : "实际计费单价<=0");
            return null;
        }
        //向下取整
        BigDecimal maxPurchaseQuantity = serviceFeeBalance.divide(currentStrategyUnitFee, 0, RoundingMode.DOWN);
        log.info("最大可购买数量计算完成，serviceFeeBalance:{}, unitFee:{}, maxPurchaseQuantity:{}",
                serviceFeeBalance, currentStrategyUnitFee, maxPurchaseQuantity);
        return maxPurchaseQuantity.max(ZERO_AMOUNT);
    }


    /**
     * 判断收费策略总开关是否开启（以 kwt_parking_strategy_switch 表为准）
     */
    private boolean isChargeStrategySwitchOpen() {
        KwtParkingStrategySwitch strategySwitch = parkingStrategySwitchRepository.queryParkingStrategySwitch();
        return strategySwitch != null && Objects.equals(strategySwitch.getStatus(), STRATEGY_OPEN);
    }

    /**
     * 查询收费策略开关配置的默认服务费
     */
    private BigDecimal resolveDefaultFee() {
        KwtParkingStrategySwitch strategySwitch = parkingStrategySwitchRepository.queryParkingStrategySwitch();
        if (strategySwitch == null || strategySwitch.getDefaultFee() == null) {
            return ZERO_AMOUNT;
        }
        return strategySwitch.getDefaultFee();
    }

    /**
     * 解析策略实际计费单价。
     * <ul>
     *     <li>无企业策略且收费策略总开关开启：使用 {@code kwt_parking_strategy_switch.default_fee}</li>
     *     <li>有企业策略且 method 为 0.00：使用开关表 default_fee</li>
     *     <li>有企业策略且 method &gt; 0：使用策略 method</li>
     * </ul>
     */
    private BigDecimal resolveStrategyUnitFee(KwtParkingChargeStrategy strategy) {
        if (strategy == null) {
            if (isChargeStrategySwitchOpen()) {
                BigDecimal defaultFee = resolveDefaultFee();
                log.info("未匹配到企业收费策略，收费策略开关已开启，使用默认单价:{}", defaultFee);
                return defaultFee;
            }
            return ZERO_AMOUNT;
        }
        BigDecimal method = strategy.getMethod() == null ? ZERO_AMOUNT : strategy.getMethod();
        if (method.compareTo(ZERO_AMOUNT) == 0) {
            return resolveDefaultFee();
        }
        return method;
    }

    /**
     * 查询企业当前绑定的收费策略（id 最大的一条，用于下单冻结/预估）。
     * 收费策略是否启用统一由 kwt_parking_strategy_switch.status 控制，不再使用策略表 status 判断。
     *
     * @param proEntId 采购企业id
     * @return 生效策略；未匹配到则返回null
     */
    private KwtParkingChargeStrategy queryCurrentEnableStrategy(Long proEntId) {
        KwtParkingChargeStrategy hitStrategy = listEnableStrategiesByProEntId(proEntId).stream()
                .max(Comparator.comparing(KwtParkingChargeStrategy::getId))
                .orElse(null);
        log.info("匹配生效策略结果，proEntId:{}, hitStrategyId:{}",
                proEntId, hitStrategy == null ? null : hitStrategy.getId());
        return hitStrategy;
    }

    /**
     * 查询采购方当前最优收费策略（实际单价最低的一条，用于订单完结扣费）。
     * 收费策略是否启用统一由 kwt_parking_strategy_switch.status 控制，不再使用策略表 status 判断。
     *
     * @param proEntId 采购企业id
     * @return 最优策略；未匹配到则返回null
     */
    private KwtParkingChargeStrategy queryOptimalEnableStrategy(Long proEntId) {
        KwtParkingChargeStrategy optimalStrategy = listEnableStrategiesByProEntId(proEntId).stream()
                .filter(item -> resolveStrategyUnitFee(item).compareTo(ZERO_AMOUNT) > 0)
                .min(Comparator.comparing(this::resolveStrategyUnitFee)
                        .thenComparing(Comparator.comparing(KwtParkingChargeStrategy::getId).reversed()))
                .orElse(null);
        log.info("匹配最优收费策略结果，proEntId:{}, optimalStrategyId:{}, unitFee:{}",
                proEntId,
                optimalStrategy == null ? null : optimalStrategy.getId(),
                optimalStrategy == null ? null : resolveStrategyUnitFee(optimalStrategy));
        return optimalStrategy;
    }

    /**
     * 查询企业已绑定的收费策略列表。
     * 收费策略总开关统一以 kwt_parking_strategy_switch.status 为准，不再使用 kwt_parking_charge_strategy.status 过滤。
     */
    private List<KwtParkingChargeStrategy> listEnableStrategiesByProEntId(Long proEntId) {
        if (!isChargeStrategySwitchOpen()) {
            log.info("收费策略总开关未开启，不查询企业收费策略绑定，proEntId:{}", proEntId);
            return List.of();
        }
        List<KwtParkingChargeStrategyUnit> strategyUnitList = parkingChangeStrategyUnitRepository.list(
                Wrappers.<KwtParkingChargeStrategyUnit>lambdaQuery()
                        .eq(KwtParkingChargeStrategyUnit::getEntId, proEntId)
                        .eq(KwtParkingChargeStrategyUnit::getDelFlag, Global.NO)
        );
        log.info("查询企业策略绑定关系，proEntId:{}, bindCount:{}",
                proEntId, strategyUnitList == null ? 0 : strategyUnitList.size());

        if (CollectionUtils.isEmpty(strategyUnitList)) {
            log.info("企业未绑定任何策略，proEntId:{}", proEntId);
            return List.of();
        }
        List<Long> strategyIds = strategyUnitList.stream()
                .map(KwtParkingChargeStrategyUnit::getStrategyId)
                .filter(Objects::nonNull)
                .toList();
        if (CollectionUtils.isEmpty(strategyIds)) {
            log.info("企业绑定策略ID集合为空，proEntId:{}", proEntId);
            return List.of();
        }
        List<KwtParkingChargeStrategy> strategyList = parkingChangeStrategyRepository.list(
                Wrappers.<KwtParkingChargeStrategy>lambdaQuery()
                        .in(KwtParkingChargeStrategy::getId, strategyIds)
                        .eq(KwtParkingChargeStrategy::getDelFlag, Global.NO)
                        .orderByDesc(KwtParkingChargeStrategy::getId)
        );
        if (CollectionUtils.isEmpty(strategyList)) {
            return List.of();
        }
        return strategyList;
    }

    /**
     * 查询企业当前可用服务费余额
     *
     * @param proEntId 采购企业id
     * @param supEntId 供应商企业id，可为空
     * @return 服务费余额，无记录时返回0
     */
    private BigDecimal queryServiceFeeBalance(Long proEntId, Long supEntId) {
        KwtParkingWalletFee walletFee = queryWalletFee(proEntId, supEntId);
        if (walletFee == null || walletFee.getServiceFeeBalance() == null) {
            log.info("查询服务费余额为空，按0处理，proEntId:{}, supEntId:{}", proEntId, supEntId);
            return ZERO_AMOUNT;
        }
        log.info("查询服务费余额成功，proEntId:{}, supEntId:{}, serviceFeeBalance:{}",
                proEntId, supEntId, walletFee.getServiceFeeBalance());
        return walletFee.getServiceFeeBalance();
    }


}
