package com.inkasso.factoring.settlement.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.inkasso.adapter.exception.BusinessException;
import com.inkasso.adapter.util.CodeUtil;
import com.inkasso.factoring.acceptanceManagement.entity.CAcceptanceGoodsInfo;
import com.inkasso.factoring.common.constant.ConstantUtil;
import com.inkasso.factoring.common.enums.PurchAccrualMarginCalcMethodDict;
import com.inkasso.factoring.dict.service.DictionaryService;
import com.inkasso.factoring.purchManagement.entity.CPurchContractBasicInfo;
import com.inkasso.factoring.purchManagement.entity.CPurchContractPriceRule;
import com.inkasso.factoring.purchManagement.entity.CPurchContractRetentionInfo;
import com.inkasso.factoring.purchManagement.service.ICPurchContractBasicInfoService;
import com.inkasso.factoring.purchManagement.service.ICPurchContractPriceRuleService;
import com.inkasso.factoring.purchManagement.service.ICPurchContractRetentionInfoService;
import com.inkasso.factoring.salesManagement.entity.CSalesContractBasicInfo;
import com.inkasso.factoring.salesManagement.entity.CSalesContractManagement;
import com.inkasso.factoring.salesManagement.entity.SalesContractApproval;
import com.inkasso.factoring.salesManagement.entity.SalesContractRetentionInfo;
import com.inkasso.factoring.salesManagement.service.ICSalesContractBasicInfoService;
import com.inkasso.factoring.salesManagement.service.ICSalesContractManagementService;
import com.inkasso.factoring.salesManagement.service.ISalesContractApprovalService;
import com.inkasso.factoring.salesManagement.service.ISalesContractRetentionInfoService;
import com.inkasso.factoring.settlement.entity.BaseGoods;
import com.inkasso.factoring.settlement.entity.SettlementGoodsInfo;
import com.inkasso.factoring.settlement.service.GoodsCalculateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * @Description : 货物计算service实现类
 * @Author : L.Jia
 * @Date: 2022-03-10 16:31
 */
@Service
public class GoodsCalculateServiceImpl implements GoodsCalculateService {

    @Autowired
    private ICSalesContractManagementService icSalesContractManagementService;

    @Autowired
    private ICSalesContractBasicInfoService salesContractBasicInfoService;

    @Autowired
    private ISalesContractRetentionInfoService salesContractRetentionInfoService;

    @Autowired
    private ICPurchContractBasicInfoService purchContractBasicInfoService;

    @Autowired
    private ICPurchContractPriceRuleService purchContractPriceRuleService;

    @Autowired
    private ICPurchContractRetentionInfoService purchContractRetentionInfoService;

    @Autowired
    private DictionaryService dictService;

    @Autowired
    private ISalesContractApprovalService iSalesContractApprovalService;


    @Override
    public List<SettlementGoodsInfo> calculateGoodsAmount(String businessNumber, Long supplierId, List<CAcceptanceGoodsInfo> goodsInfoList,
                                                BigDecimal occupationSalesRetention, BigDecimal occupationPurchRetention) {
        if (goodsInfoList != null && goodsInfoList.size() > 0) {
            List<SettlementGoodsInfo> goodsList = goodsInfoList.stream().map(goodsInfo -> {
                // 计算货物销售总价、销售质保金、采购总价、采购质保金信息
                goodsInfo.setSalesPrice(goodsInfo.getReferencePrice().add(goodsInfo.getFloatingPrice()));
                SettlementGoodsInfo baseGoods = calculate(businessNumber, supplierId,
                        goodsInfo.getSalesPrice(), goodsInfo.getGoodsQuantity());
                baseGoods.setAcceptanceGoodsInfoId(goodsInfo.getId());
                baseGoods.setcAcceptanceBasicInfoId(goodsInfo.getcAcceptanceBasicInfoId());
                baseGoods.setReferencePrice(goodsInfo.getReferencePrice());
                baseGoods.setFloatingPrice(goodsInfo.getFloatingPrice());
                baseGoods.setSalesPrice(goodsInfo.getSalesPrice());
                return baseGoods;
            }).collect(Collectors.toList());

            //计算销售质保金
            SalesContractRetentionInfo salesContractRetention = getSalesContractRetentionInfo(businessNumber);
            if (salesContractRetention != null && salesContractRetention.getRetention()) {
                if (salesContractRetention.getTop()) {
                    //如果质保金有上限，校正销售质保金金额
                    BigDecimal retentionLimit = salesContractRetention.getRetentionLimit();
                    if (retentionLimit == null) {
                        throw new BusinessException(CodeUtil.FAIL, "销售质保金上限不能为空");
                    }
                    BigDecimal surplus = retentionLimit.subtract(occupationSalesRetention);
                    if (surplus.compareTo(BigDecimal.ZERO) > 0) {
                        goodsList = calculateSalesGuaranteeMoney(surplus, goodsList);
                    } else if (surplus.compareTo(BigDecimal.ZERO) == 0) {
                        for (BaseGoods baseGoods : goodsList) {
                            baseGoods.setSalesGuaranteeMoney(BigDecimal.ZERO.setScale(4, BigDecimal.ROUND_HALF_UP));
                        }
                    }
                }
            }

            //计算采购质保金
            CPurchContractRetentionInfo purchContractRetention = getPurchContractRetentionInfo(businessNumber, supplierId);
            if (purchContractRetention != null && purchContractRetention.getRetention()) {
                if (purchContractRetention.getTop()) {
                    //如果质保金有上限，校正销售质保金金额
                    BigDecimal retentionLimit = purchContractRetention.getRetentionLimit();
                    if (retentionLimit == null) {
                        throw new BusinessException(CodeUtil.FAIL, "采购质保金上限不能为空");
                    }
                    BigDecimal surplus = retentionLimit.subtract(occupationPurchRetention);
                    if (surplus.compareTo(BigDecimal.ZERO) > 0) {
                        goodsList = calculatePurchGuaranteeMoney(surplus, goodsList);
                    } else if (surplus.compareTo(BigDecimal.ZERO) == 0) {
                        for (BaseGoods baseGoods : goodsList) {
                            baseGoods.setPurchaseGuaranteeMoney(BigDecimal.ZERO);
                        }
                    }
                }
            }
            return goodsList;
        }

        return null;
    }

    public SettlementGoodsInfo calculate(String businessNumber, Long supplierId, BigDecimal salesPrice, BigDecimal goodsQuantity) {
        SettlementGoodsInfo goodsInfo = new SettlementGoodsInfo();
        //计算销售总价=销售单价*数量，保留4位小数
        salesPrice = salesPrice == null ? BigDecimal.ZERO : salesPrice;
        BigDecimal salesTotalPrice = salesPrice.multiply(goodsQuantity)
                .setScale(4, RoundingMode.HALF_UP);
        goodsInfo.setSalesTotalPrice(salesTotalPrice);

        //计算销售质保金=销售总价*销售合同中的质保金比例
        SalesContractRetentionInfo retentionInfo = getSalesContractRetentionInfo(businessNumber);
        if (retentionInfo != null && retentionInfo.getRetention()) {
            BigDecimal salesGuaranteeMoney = salesTotalPrice.multiply(retentionInfo.getRetentionPercent())
                    .divide(new BigDecimal(100), 4, RoundingMode.HALF_UP);
            goodsInfo.setSalesGuaranteeMoney(salesGuaranteeMoney);
        }
        //计算采购相关金额
        CPurchContractBasicInfo purchContractBasicInfo = purchContractBasicInfoService.findByBusinessNumberAndSupplierId(businessNumber, supplierId);
        CPurchContractPriceRule priceRule = purchContractPriceRuleService.getOne(new QueryWrapper<CPurchContractPriceRule>()
                .eq("c_purch_contract_basic_info_id", purchContractBasicInfo.getId()));

        BigDecimal purchasePrice = BigDecimal.ZERO;
        if (priceRule.getAccrualMarginCalcMethod().equals(1)) {
            //如果利差计算规则=固定差额  采购单价=销售单价-差额
            purchasePrice = salesPrice.subtract(priceRule.getDifferAmount() == null ? BigDecimal.ZERO : priceRule.getDifferAmount());
        }
        if (priceRule.getAccrualMarginCalcMethod().equals(0)) {
            //如果利差计算规则=固定利率 采购单价=销售单价-销售单价*(月利率)*（预估保理融资期限/30），--不足30按30算
            //月利率
            BigDecimal monthlyRate = priceRule.getMonthlyInterestRate().divide(new BigDecimal(100));
            //预估保理融资期限/30），--不足30按30算
            BigDecimal param = new BigDecimal(priceRule.getFactoringFinanceDeadline()).divide(new BigDecimal("30"), RoundingMode.UP);
            purchasePrice = salesPrice.subtract(salesPrice.multiply(monthlyRate).multiply(param)).setScale(4, RoundingMode.HALF_UP);
        }
        goodsInfo.setPurchasePrice(purchasePrice);

        //采购总价
        BigDecimal purchaseTotalPrice = purchasePrice.multiply(goodsQuantity).setScale(4, RoundingMode.HALF_UP);
        goodsInfo.setPurchaseTotalPrice(purchaseTotalPrice);

        //采购质保金
        CPurchContractRetentionInfo purchContractRetentionInfo = purchContractRetentionInfoService.getOne(new QueryWrapper<CPurchContractRetentionInfo>()
                .eq("c_purch_contract_basic_info_id", purchContractBasicInfo.getId()));
        if (purchContractRetentionInfo != null && purchContractRetentionInfo.getRetention()) {
            BigDecimal purchaseGuaranteeMoney = purchaseTotalPrice.multiply(purchContractRetentionInfo.getRetentionPercent())
                    .divide(new BigDecimal(100), 4, RoundingMode.HALF_UP);
            goodsInfo.setPurchaseGuaranteeMoney(purchaseGuaranteeMoney);
        }
        return goodsInfo;
    }

    public List<SettlementGoodsInfo> calculateSalesGuaranteeMoney(BigDecimal surplusAmount, List<SettlementGoodsInfo> goodsList) {

        //分配销售质保金
        BigDecimal guaranteeMoneyTotal = goodsList.stream().filter(goods -> goods.getSalesGuaranteeMoney() != null)
                .map(BaseGoods::getSalesGuaranteeMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (surplusAmount.compareTo(guaranteeMoneyTotal) >= 0) {
            //如果质保金上限大于等于货物质保金之和
            return goodsList;
        } else {
            //如果质保金上限小于货物质保金之和，需要重新分配
            for (BaseGoods baseGoods : goodsList) {
                if (baseGoods.getSalesGuaranteeMoney() != null) {
                    BigDecimal currentGuaranteeMoney = baseGoods.getSalesGuaranteeMoney();
                    if (baseGoods.getSalesGuaranteeMoney().compareTo(surplusAmount) >= 0) {
                        currentGuaranteeMoney = surplusAmount.setScale(4, RoundingMode.HALF_UP);
                    }
                    baseGoods.setSalesGuaranteeMoney(currentGuaranteeMoney);
                    surplusAmount = surplusAmount.subtract(currentGuaranteeMoney);
                }
            }
        }
        return goodsList;
    }

    public List<SettlementGoodsInfo> calculatePurchGuaranteeMoney(BigDecimal surplusAmount, List<SettlementGoodsInfo> goodsList) {

        //分配采购质保金
        BigDecimal guaranteeMoneyTotal = goodsList.stream().filter(goods -> goods.getPurchaseGuaranteeMoney() != null)
                .map(BaseGoods::getPurchaseGuaranteeMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        if (surplusAmount.compareTo(guaranteeMoneyTotal) >= 0) {
            //如果质保金上限大于等于货物质保金之和
            return goodsList;
        } else {
            //如果质保金上限小于货物质保金之和，需要重新分配
            for (BaseGoods baseGoods : goodsList) {
                if (baseGoods.getPurchaseGuaranteeMoney() != null) {
                    BigDecimal currentGuaranteeMoney = baseGoods.getPurchaseGuaranteeMoney();
                    if (baseGoods.getPurchaseGuaranteeMoney().compareTo(surplusAmount) >= 0) {
                        currentGuaranteeMoney = surplusAmount.setScale(4, RoundingMode.HALF_UP);
                    }
                    baseGoods.setPurchaseGuaranteeMoney(currentGuaranteeMoney);
                    surplusAmount = surplusAmount.subtract(currentGuaranteeMoney);
                }
            }
        }
        return goodsList;
    }


    /**
     * 获取销售质保金信息
     *
     * @param businessNumber
     * @return
     */
    public SalesContractRetentionInfo getSalesContractRetentionInfo(String businessNumber) {
        CSalesContractManagement salesContractManagement = icSalesContractManagementService.getByBusinessNumber(businessNumber);
        if (salesContractManagement == null || salesContractManagement.getId() == null) {
            throw new BusinessException(CodeUtil.FAIL, "销售合同管理不能为空");
        }
        CSalesContractBasicInfo salesContractBasicInfo = salesContractBasicInfoService.getOne(new QueryWrapper<CSalesContractBasicInfo>()
                        .eq("c_sales_contract_management_id",salesContractManagement.getId()));
        if (salesContractBasicInfo == null || salesContractBasicInfo.getId() == null) {
            throw new BusinessException(CodeUtil.FAIL, "销售合同基础信息不能为空");
        }
        SalesContractApproval salesContractApproval = iSalesContractApprovalService.getOne(new QueryWrapper<SalesContractApproval>().eq("c_sales_contract_basic_info_id", salesContractBasicInfo.getId())
                .eq("approval_conclusion", ConstantUtil.PASS).orderByDesc("gmt_create").last("LIMIT 1"));
        QueryWrapper<SalesContractRetentionInfo> queryWrapper = new QueryWrapper();
        queryWrapper.eq("sales_contract_approval_id",salesContractApproval.getId());
        return salesContractRetentionInfoService.getOne(queryWrapper) ;
    }

    public CPurchContractRetentionInfo getPurchContractRetentionInfo(String businessNumber, Long supplierId) {

        CPurchContractBasicInfo purchContractBasicInfo = purchContractBasicInfoService.findByBusinessNumberAndSupplierId(businessNumber, supplierId);
        if (purchContractBasicInfo != null && purchContractBasicInfo.getId() != null) {
            return purchContractRetentionInfoService.getOne(new QueryWrapper<CPurchContractRetentionInfo>()
                    .eq("c_purch_contract_basic_info_id", purchContractBasicInfo.getId()));
        }
        return null;
    }
}
