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

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.prolog.framework.common.message.RestMessage;
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.LoadingBillPriceDTO;
import com.prolog.rdc.tms.model.dto.SySParameterDTO;
import com.prolog.rdc.tms.model.entity.*;
import com.prolog.rdc.tms.rmi.feign.MaindataFeign;
import com.prolog.rdc.tms.service.strategy.PayAbstractSplitStrategyRuleHandler;
import com.prolog.rdc.tms.service.strategy.PayCostStrategyRuleHandler;
import org.apache.ibatis.plugin.PluginException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;

@Component
@PayCostStrategyRuleHandler(BmsConstant.LADDER_COST)
public class PayLadderPriceStrategy extends PayAbstractSplitStrategyRuleHandler {

    private final Logger logger = LoggerFactory.getLogger(PayLadderPriceStrategy.class);

    @Autowired
    private LadderCostStrategyMapper strategyMapper;

    @Autowired
    private MaindataFeign maindataTmsResource;

    @Autowired
    private BmsBillPayFeeDetailMapper bmsBillPayFeeDetailMapper;

    @Autowired
    private ShipBillFeeTemporaryDetailMapper temporaryDetailMapper;
    @Autowired
    private ExpenseManagementMapper managementMapper;
    @Autowired
    private ExpenseAccountMapper expenseAccountMapper;

    /**
     * 派车单执行阶梯计费
     *
     * @param priceModel   计费数据
     * @param costStrategy 运单信息
     */
    public List<LoadingBillPriceDTO> executeStrategyLoading(BmsLogisticsContractModel contractModel, BmsFreightPriceModel priceModel, BmsLoadingBillHeaderModel costStrategy, String source,UserEntity user) {

        logger.info("执行阶梯计费开始...." + JSONObject.toJSONString(priceModel));
        Integer ladderType = priceModel.getLadderType();
        // 查询阶梯数据
        Criteria criteria = Criteria.forClass(BmsFreightPriceLadderModel.class);
        Restriction r1 = Restrictions.eq("priceNo", priceModel.getPriceNo());
        Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2));
        List<BmsFreightPriceLadderModel> ladderModels = strategyMapper.findByCriteria(criteria);
        if (ObjectUtil.isEmpty(ladderModels)) {
            throw new PluginException("阶梯信息为空，请先维护");
        }
        // 获取总量
        if (ObjectUtil.isEmpty(costStrategy.getTotalPayWeight())) {
            throw new PluginException("总重量不能为空");
        }
        RestMessage<SySParameterDTO> parameterModel = maindataTmsResource.queryParameter();
        if (ObjectUtil.isEmpty(parameterModel) || !parameterModel.isSuccess()) {
            throw new PluginException("系统参数未配置");
        }
        SySParameterDTO parameterDTO = parameterModel.getData();

        // 1.通过查询区间 获取单价
        BigDecimal price = BigDecimal.valueOf(0);
        BigDecimal totWeight = costStrategy.getTotalPayWeight();

        // 里程
        BigDecimal totalMileage = costStrategy.getTotalPayMileage();
        if (ObjectUtil.isEmpty(totalMileage) || NumberUtil.equals(BigDecimal.ZERO,totalMileage)) {
            totalMileage = priceModel.getMileage();
        }
        String modelLadderType = null;
        boolean flag = false;
        for (BmsFreightPriceLadderModel ladderModel : ladderModels) {
            // 1:大于，2：小于等于
            if (ladderType == 1) {
                // 按重量找区间
                Boolean isMatch = matchPriceLadder(ladderModel,totWeight);
                if (Boolean.TRUE.equals(isMatch)) {
                    price = ladderModel.getPrice();
                    modelLadderType = ladderModel.getLadderType();
                    flag = true;
                    break;
                }
            } else if (ladderType == 2) {
                // 按里程找区间
                Boolean isMatch = matchPriceLadder(ladderModel,totalMileage);
                if (Boolean.TRUE.equals(isMatch)) {
                    price = ladderModel.getPrice();
                    modelLadderType = ladderModel.getLadderType();
                    flag = true;
                    break;
                }
            }
        }
        if (!flag) {
            throw new PluginException("没有匹配到阶梯数据");
        }
        BigDecimal totPrice = new BigDecimal(0);
        // 1.按KG
        if (ladderType == 1) {
            if (priceModel.getSettlementType() == 2) {
                // 2.元/kg
                totPrice = this.calculateForPrice(parameterDTO, totWeight, price);
            }
        }
        // 2.按公里
        if (ladderType == 2) {
            if (priceModel.getSettlementType() == 4) {
                // 1.元/公里
                totPrice = this.calculateTwoForMileage(parameterDTO, totalMileage, price);
            }
        }
        List<LoadingBillPriceDTO> list = Lists.newArrayList();
        LoadingBillPriceDTO dto = new LoadingBillPriceDTO();
        dto.setPrice(totPrice);
        dto.setLoadingId(costStrategy.getId());
        dto.setLoadingBillNo(costStrategy.getLoadingBillNo());
        dto.setCostContract(contractModel.getContractName());
        dto.setCostPriceTable(priceModel.getPriceName());
        dto.setFirstPartyId(contractModel.getFirstPartyId());
        dto.setFirstPartyCode(contractModel.getFirstPartyCode());
        dto.setFirstPartyName(contractModel.getFirstPartyName());

        this.saveFee(costStrategy.getLoadingBillNo(),costStrategy.getId(), contractModel, priceModel, user, modelLadderType, totPrice, source);
        list.add(dto);
        return list;
    }

    private void saveFee(String billNo,Long billId, BmsLogisticsContractModel contractModel, BmsFreightPriceModel priceModel, UserEntity user, String modelLadderType, BigDecimal totPrice, String source) {
        // 新增费用信息
        BmsBillPayFeeDetailModel feeDetailModel = new BmsBillPayFeeDetailModel();
        RestMessage<String> expenseNo = maindataTmsResource.getCodeNumberByCode(BmsConstant.SHIP_BILL_EXPENSE_NO, "L");
        if (!expenseNo.isSuccess() || ObjectUtil.isEmpty(expenseNo)) {
            throw new PluginException("获取费用单号为空");
        }
        feeDetailModel.setExpenseNo(expenseNo.getData());
        feeDetailModel.setBillId(billId);
        feeDetailModel.setBillNo(billNo);
        feeDetailModel.setExpenseTypeName("运费");
        feeDetailModel.setBillingSource(1);
        feeDetailModel.setBillingStatus(1);
        feeDetailModel.setBillingDate(DateUtil.date());
        feeDetailModel.setBillingContract(contractModel.getContractName());
        feeDetailModel.setBillingPrice(priceModel.getPriceName());
        feeDetailModel.setPayFeeType(2);
        //  费用编码、费用名称、费用科目名称、费用科目编码、费用类型 为价格表的费用反写（只有附加费才有）
        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());
        RestMessage<SySParameterDTO> parameterModel = maindataTmsResource.queryParameter();
        int taxPoint = Integer.parseInt(contractModel.getTaxPoint());
        if (ObjectUtil.isNotEmpty(parameterModel) && parameterModel.isSuccess()) {
            // 1：含税，2：未税
            Integer isTax = parameterModel.getData().getDriverPriceType();
            // 含税金额 = 未税金额（1 + 税点）
            BigDecimal point = BigDecimal.valueOf(taxPoint).divide(BigDecimal.valueOf(100), 5, RoundingMode.HALF_UP).add(BigDecimal.valueOf(1));
            Integer costPrecision = parameterModel.getData().getCostPrecision();
            Integer costInteger = parameterModel.getData().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()));
            }
        } else {
            throw new PluginException("获取系统配置不存在");
        }
        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);
        }
    }

    private BigDecimal calculateTwoForMileage(SySParameterDTO parameterDTO, BigDecimal totalMileage, BigDecimal price) {
        // 计算总金额
        Integer costInteger = parameterDTO.getCostInteger();
        Integer costPrecision = parameterDTO.getCostPrecision();
        BigDecimal totPrice = new BigDecimal(0);
        if (costInteger == 1) {
            totPrice = price.multiply(totalMileage).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP);
        }
        // 向上取整
        if (costInteger == 2) {
            totPrice = price.multiply(totalMileage).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP);
        }
        // 向下取整
        if (costInteger == 3) {
            totPrice = price.multiply(totalMileage).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN);
        }
        return totPrice;
    }

    // 2.元/kg
    private BigDecimal calculateForPrice(SySParameterDTO parameterDTO,BigDecimal totWeight, BigDecimal price) {
        // 总量
        // 计算总金额
        Integer costInteger = parameterDTO.getCostInteger();
        Integer costPrecision = parameterDTO.getCostPrecision();

        BigDecimal totPrice = new BigDecimal(0);
        if (costInteger == 1) {
            totPrice = price.multiply(totWeight).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP);
        }
        // 向上取整
        if (costInteger == 2) {
            totPrice = price.multiply(totWeight).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP);
        }
        // 向下取整
        if (costInteger == 3) {
            totPrice = price.multiply(totWeight).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN);
            ;
        }
        return totPrice;
    }
    // 匹配价格阶梯
    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;
    }
}