package com.prolog.rdc.tms.service.executeStrategy;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.product.core.framework.entity.UserEntity;
import com.prolog.rdc.tms.constant.BmsConstant;
import com.prolog.rdc.tms.dao.mapper.*;
import com.prolog.rdc.tms.model.dto.ShipBillPriceDTO;
import com.prolog.rdc.tms.model.dto.SySParameterDTO;
import com.prolog.rdc.tms.model.entity.*;
import com.prolog.rdc.tms.proxy.MainDataProxy;
import com.prolog.rdc.tms.service.strategy.AbstractSplitStrategyRuleHandler;
import com.prolog.rdc.tms.service.strategy.CostStrategyRuleHandler;
import org.apache.ibatis.plugin.PluginException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

/**
 * @author hongbo.pan
 * @date 2023/10/10
 */
@Component
@CostStrategyRuleHandler(BmsConstant.JD_LADDER_COST)
public class JdLadderForPackageStrategy extends AbstractSplitStrategyRuleHandler {

    @Autowired
    private LadderCostStrategyMapper strategyMapper;

    @Autowired
    private BmsShipBillPackageMapper shipBillPackageMapper;

    @Autowired
    private MainDataProxy mainDataProxy;

    @Autowired
    private BmsBillPayFeeDetailMapper bmsBillPayFeeDetailMapper;

    @Autowired
    private ShipBillFeeTemporaryDetailMapper temporaryDetailMapper;

    @Autowired
    private ExpenseManagementMapper managementMapper;

    @Autowired
    private ExpenseAccountMapper expenseAccountMapper;

    @Override
    public List<ShipBillPriceDTO> executeStrategy(BmsLogisticsContractModel contractModel, BmsFreightPriceModel priceModel, BmsShipBillHeaderModel shipBillHeader, String source, UserEntity user) {
        Integer ladderType = priceModel.getLadderType();
        if (ladderType != 1) {
            throw new PluginException("京东阶梯计费只支持【按KG】阶梯方式");
        }
        if (priceModel.getSettlementType() != 2) {
            throw new PluginException("京东阶梯计费只支持【元/千克】计费方式");
        }
        // 查询阶梯数据
        Criteria criteria = Criteria.forClass(BmsFreightPriceLadderModel.class);
        Restriction r1 = Restrictions.eq(BmsFreightPriceLadderModel::getPriceNo, priceModel.getPriceNo());
        Restriction r2 = Restrictions.eq(BmsFreightPriceLadderModel::getEnterpriseId, user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2));
        List<BmsFreightPriceLadderModel> ladderList = strategyMapper.findByCriteria(criteria);
        if (CollUtil.isEmpty(ladderList)) {
            throw new PluginException("阶梯信息为空，请先维护");
        }

        criteria = Criteria.forClass(BmsShipBillPackageModel.class);
        r1 = Restrictions.eq(BmsShipBillPackageModel::getShipbillNo, shipBillHeader.getShipbillNo());
        r2 = Restrictions.eq(BmsShipBillPackageModel::getEnterpriseId, user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2));
        List<BmsShipBillPackageModel> packageList =  shipBillPackageMapper.findByCriteria(criteria);
        if (CollUtil.isEmpty(packageList)) {
            throw new PluginException("计费失败，运单包裹信息不存在");
        }
        SySParameterDTO parameterDTO = mainDataProxy.queryParameter();
        Integer costInteger = parameterDTO.getCostInteger();
        Integer costPrecision = parameterDTO.getCostPrecision();
        RoundingMode roundingMode = RoundingMode.HALF_UP;
        if (costInteger == 2) {
            roundingMode = RoundingMode.UP;
        }
        if (costInteger == 3) {
            roundingMode = RoundingMode.DOWN;
        }
        RoundingMode finalRoundingMode = roundingMode;
        return packageList.stream().map(packageModel -> {
            BigDecimal totalWeight = NumberUtil.null2Zero(packageModel.getPackageTotalWeight());//200.39
            List<BmsFreightPriceLadderModel> filterLadderList = ladderList.stream().filter(ladder ->
                    matchPriceLadder(ladder, totalWeight)).collect(Collectors.toList());
            if (CollUtil.isEmpty(filterLadderList)) {
                throw new PluginException("包裹【"+packageModel.getPackageCode()+"】重量【"+totalWeight.stripTrailingZeros().toPlainString()+"】未找到重量区间，请检查报价！");
            }
            BmsFreightPriceLadderModel ladderModel = filterLadderList.get(0);
            //首重
            BigDecimal initialLadder = NumberUtil.null2Zero(ladderModel.getInitialLadder());//51
            //首重单价
            BigDecimal initialLadderPrice = NumberUtil.null2Zero(ladderModel.getInitialLadderPrice());//1
            BigDecimal amt = BigDecimal.ZERO;
            if (ladderModel.getCalculateRule().equals(1)) {
                //首重 + 续重
                //首重单价
                amt = initialLadderPrice;
                if (NumberUtil.isGreater(totalWeight, initialLadder)) {
                    //首重单价 + （包裹重量 - 首重） * 续重单价
                    amt = NumberUtil.add(amt, NumberUtil.mul(NumberUtil.sub(totalWeight, initialLadder), ladderModel.getPrice()));
                }
            } else {
                //重量一口价
                if (NumberUtil.isGreater(NumberUtil.mul(totalWeight, ladderModel.getPrice()), NumberUtil.null2Zero(ladderModel.getStartingPrice()))) {
                    //包裹重量 * 续重单价
                    amt = NumberUtil.mul(totalWeight, ladderModel.getPrice());
                } else {
                    //起步价
                    amt = NumberUtil.null2Zero(ladderModel.getStartingPrice());
                }

            }
            amt = NumberUtil.round(amt, costPrecision, finalRoundingMode);
            ShipBillPriceDTO shipBillPriceDTO = new ShipBillPriceDTO();
            shipBillPriceDTO.setPrice(amt);
            shipBillPriceDTO.setPackageId(packageModel.getId());
            shipBillPriceDTO.setPackageCode(packageModel.getPackageCode());
            shipBillPriceDTO.setShipbillNo(shipBillHeader.getShipbillNo());
            shipBillPriceDTO.setCostContract(contractModel.getContractName());
            shipBillPriceDTO.setCostPriceTable(priceModel.getPriceName());
            shipBillPriceDTO.setFirstPartyId(contractModel.getFirstPartyId());
            shipBillPriceDTO.setFirstPartyCode(contractModel.getFirstPartyCode());
            shipBillPriceDTO.setFirstPartyName(contractModel.getFirstPartyName());
            saveFee(shipBillHeader, contractModel, priceModel, user, ladderModel.getLadderType(), amt, source, shipBillPriceDTO, parameterDTO);
            return shipBillPriceDTO;
        }).collect(Collectors.toList());
    }

    // 匹配价格阶梯
    public Boolean matchPriceLadder(BmsFreightPriceLadderModel ladderModel,BigDecimal cmpVal) {
        if (ObjectUtil.isNotEmpty(ladderModel.getSectionDown()) && ObjectUtil.isEmpty(ladderModel.getSectionUp())) {
            if (ladderModel.getSectionDownSymbol() == 1) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) > 0)) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionDownSymbol() == 2) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) >= 0)) {
                    return Boolean.TRUE;
                }
            }
        } else if (ObjectUtil.isEmpty(ladderModel.getSectionDown()) && ObjectUtil.isNotEmpty(ladderModel.getSectionUp())) {
            if (ladderModel.getSectionUpSymbol() == 1) {
                if ((cmpVal.compareTo(ladderModel.getSectionUp()) < 0)) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionUpSymbol() == 2) {
                if ((cmpVal.compareTo(ladderModel.getSectionUp()) <= 0)) {
                    return Boolean.TRUE;
                }
            }
        } else if (ObjectUtil.isNotEmpty(ladderModel.getSectionDown()) && ObjectUtil.isNotEmpty(ladderModel.getSectionUp())) {
            if (ladderModel.getSectionDownSymbol() == 1 && ladderModel.getSectionUpSymbol() == 1) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) > 0) && cmpVal.compareTo(ladderModel.getSectionUp()) < 0) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionDownSymbol() == 1 && ladderModel.getSectionUpSymbol() == 2) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) > 0) && cmpVal.compareTo(ladderModel.getSectionUp()) <= 0) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionDownSymbol() == 2 && ladderModel.getSectionUpSymbol() == 1) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) >= 0) && cmpVal.compareTo(ladderModel.getSectionUp()) < 0) {
                    return Boolean.TRUE;
                }
            } else if (ladderModel.getSectionDownSymbol() == 2 && ladderModel.getSectionUpSymbol() == 2) {
                if ((cmpVal.compareTo(ladderModel.getSectionDown()) >= 0) && cmpVal.compareTo(ladderModel.getSectionUp()) <= 0) {
                    return Boolean.TRUE;
                }
            }
        }
        return Boolean.FALSE;
    }

    protected void saveFee(BmsShipBillHeaderModel costStrategy, BmsLogisticsContractModel contractModel, BmsFreightPriceModel priceModel, UserEntity user, String modelLadderType, BigDecimal totPrice, String source, ShipBillPriceDTO dto, SySParameterDTO parameterDTO) {
        // 新增费用信息
        BmsBillPayFeeDetailModel feeDetailModel = new BmsBillPayFeeDetailModel();
        String expenseNo = mainDataProxy.getCodeNumberByCode(BmsConstant.SHIP_BILL_EXPENSE_NO);
        feeDetailModel.setExpenseNo(expenseNo);
        feeDetailModel.setBillNo(costStrategy.getShipbillNo());
        feeDetailModel.setBillId(costStrategy.getId());
        feeDetailModel.setPayFeeType(1);
        feeDetailModel.setExpenseTypeName("运费");
        feeDetailModel.setBillingSource(1);
        feeDetailModel.setBillingStatus(1);
        feeDetailModel.setBillingDate(DateUtil.date());
        feeDetailModel.setBillingContract(contractModel.getContractName());
        feeDetailModel.setBillingPrice(priceModel.getPriceName());
        feeDetailModel.setPackageId(dto.getPackageId());
        feeDetailModel.setPackageCode(dto.getPackageCode());
        //  费用编码、费用名称、费用科目名称、费用科目编码、费用类型 为价格表的费用反写（只有附加费才有）
        String expenseName = priceModel.getExpenseName();
        Criteria forClass = Criteria.forClass(BmsExpenseManagementModel.class);
        Restriction r7 = Restrictions.eq("status", 1);
        Restriction r8 = Restrictions.eq("expenseName", expenseName);
        Restriction r9 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        forClass.setRestriction(Restrictions.and(r7, r8,r9));
        List<BmsExpenseManagementModel> managementModels = managementMapper.findByCriteria(forClass);
        if (ObjectUtil.isEmpty(managementModels)) {
            throw new PluginException("获取费用信息失败");
        }
        BmsExpenseManagementModel managementModel = managementModels.get(0);
        feeDetailModel.setExpenseCode(managementModel.getExpenseCode());
        feeDetailModel.setExpenseName(managementModel.getExpenseName());
        feeDetailModel.setExpenseAccountCode(managementModel.getExpenseAccountCode());
        feeDetailModel.setExpenseAccountName(managementModel.getExpenseAccountName());
        // 支出，收入
        String expenseAccountCode = managementModel.getExpenseAccountCode();
        Criteria aClass = Criteria.forClass(ExpenseAccountModel.class);
        Restriction r11 = Restrictions.eq("expenseCode", expenseAccountCode);
        Restriction r12 = Restrictions.eq("status", 1);
        aClass.setRestriction(Restrictions.and(r11, r12));
        List<ExpenseAccountModel> mapper = expenseAccountMapper.findByCriteria(aClass);
        if (ObjectUtil.isNotEmpty(mapper)) {
            feeDetailModel.setExpenseType(mapper.get(0).getExpenseClassify());
            feeDetailModel.setExpenseTypeName(Objects.equals(mapper.get(0).getExpenseClassify(), 1) ? "收入" : "支出");
        }

        feeDetailModel.setTaxPoint(contractModel.getTaxPoint());
        int taxPoint = Integer.parseInt(contractModel.getTaxPoint());
        // 1：含税，2：未税
        Integer isTax = parameterDTO.getIsTax();
        // 含税金额 = 未税金额（1 + 税点）
        BigDecimal point = BigDecimal.valueOf(taxPoint).divide(BigDecimal.valueOf(100), 5, RoundingMode.HALF_UP).add(BigDecimal.valueOf(1));
        Integer costPrecision = parameterDTO.getCostPrecision();
        Integer costInteger = parameterDTO.getCostInteger();
        if (isTax == 1) {
            // 四舍五入
            if (costInteger == 1) {
                feeDetailModel.setNoTaxAmt(totPrice.divide(point, costPrecision, RoundingMode.HALF_UP));
                feeDetailModel.setTaxAmt(totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP));
            }
            // 向上取整
            if (costInteger == 2) {
                feeDetailModel.setNoTaxAmt(totPrice.divide(point, costPrecision, RoundingMode.UP));
                feeDetailModel.setTaxAmt(totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP));
            }
            // 向下取整
            if (costInteger == 3) {
                feeDetailModel.setNoTaxAmt(totPrice.divide(point, costPrecision, RoundingMode.DOWN));
                feeDetailModel.setTaxAmt(totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN));
            }
            feeDetailModel.setTax(feeDetailModel.getTaxAmt().subtract(feeDetailModel.getNoTaxAmt()));
        } else {
            // 四舍五入
            if (costInteger == 1) {
                feeDetailModel.setNoTaxAmt(totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP));
                feeDetailModel.setTaxAmt(totPrice.multiply(point).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP));
            }
            // 向上取整
            if (costInteger == 2) {
                feeDetailModel.setNoTaxAmt(totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP));
                feeDetailModel.setTaxAmt(totPrice.multiply(point).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP));
            }
            // 向下取整
            if (costInteger == 3) {
                feeDetailModel.setNoTaxAmt(totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN));
                feeDetailModel.setTaxAmt(totPrice.multiply(point).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN));
            }
            feeDetailModel.setTax(feeDetailModel.getTaxAmt().subtract(feeDetailModel.getNoTaxAmt()));
        }
        feeDetailModel.setBillingType(modelLadderType);
        feeDetailModel.setCreateperson(user.getNickname());
        feeDetailModel.setCreatetime(DateUtil.date());
        feeDetailModel.setUpdateperson(user.getNickname());
        feeDetailModel.setUpdatetime(DateUtil.date());
        feeDetailModel.setEnterpriseId(user.getEnterpriseId());
        feeDetailModel.setEnterpriseName(user.getEnterpriseName());
        feeDetailModel.setExpenseStatus(2);
        feeDetailModel.setCheckStatus(0);
        // 0：试验，1：非试验
        if (source.equals("0")) {
            BmsShipBillFeeTemporaryDetailModel temporaryDetailModel = new BmsShipBillFeeTemporaryDetailModel();
            BeanUtils.copyProperties(feeDetailModel, temporaryDetailModel);
            temporaryDetailMapper.save(temporaryDetailModel);
        } else {
            bmsBillPayFeeDetailMapper.save(feeDetailModel);
        }
    }
}
