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

import cn.hutool.core.date.DateUtil;
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.Order;
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.product.core.framework.util.PlgFxUsrUtils;
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.rmi.feign.MaindataFeign;
import com.prolog.rdc.tms.service.strategy.AbstractSplitStrategyRuleHandler;
import com.prolog.rdc.tms.service.strategy.CostStrategyRuleHandler;
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.Date;
import java.util.List;
import java.util.Objects;

@Component
@CostStrategyRuleHandler(BmsConstant.PRICE_TIME)
public class TimePriceStrategy extends AbstractSplitStrategyRuleHandler {

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

    @Autowired
    private TimeBillStrategyMapper timeBillStrategyMapper;
    @Autowired
    private MaindataFeign maindataTmsResource;
    @Autowired
    private BmsBillPayFeeDetailMapper bmsBillPayFeeDetailMapper;
    @Autowired
    private ShipBillFeeTemporaryDetailMapper temporaryDetailMapper;
    @Autowired
    private ExpenseManagementMapper managementMapper;
    @Autowired
    private ExpenseAccountMapper expenseAccountMapper;
    @Autowired
    private TimeBillStrategyLadderMapper timeBillStrategyLadderMapper;
    /**
     * 按时间计费
     *
     * @param priceModel   计费数据
     * @param costStrategy 运单信息
     */
    @Override
    public List<ShipBillPriceDTO> executeStrategy(BmsLogisticsContractModel contractModel, BmsFreightPriceModel priceModel, BmsShipBillHeaderModel costStrategy,String source,UserEntity user) {
        logger.info("执行按时间计费...." + JSONObject.toJSONString(costStrategy));
        // 1.查询时间策略
        BigDecimal hours = this.getHours(costStrategy,priceModel,user);
        BigDecimal totPrice = hours.multiply(priceModel.getPrice());
        List<ShipBillPriceDTO> list = Lists.newArrayList();
        ShipBillPriceDTO dto = new ShipBillPriceDTO();
        dto.setPrice(totPrice.divide(BigDecimal.valueOf(1),2,RoundingMode.HALF_UP));
        dto.setShipbillNo(costStrategy.getShipbillNo());
        dto.setCostContract(contractModel.getContractName());
        dto.setCostPriceTable(priceModel.getPriceName());
        dto.setFirstPartyId(contractModel.getFirstPartyId());
        dto.setFirstPartyCode(contractModel.getFirstPartyCode());
        dto.setFirstPartyName(contractModel.getFirstPartyName());
        this.saveFee(dto,costStrategy,contractModel,priceModel,user,totPrice, source);
        list.add(dto);
        return list;
    }

    private BigDecimal getHours(BmsShipBillHeaderModel costStrategy,BmsFreightPriceModel priceModel,UserEntity user) {
        Criteria criteria = Criteria.forClass(BmsTimeBillStrategyModel.class);
        Restriction r1 = Restrictions.eq("status", 1);
        Restriction r2 = Restrictions.eq("id", priceModel.getTimeStrategyId());
        Restriction r3 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2,r3));
        criteria.setOrder(Order.newInstance().desc("updatetime"));
        List<BmsTimeBillStrategyModel> models = timeBillStrategyMapper.findByCriteria(criteria);
        if (ObjectUtil.isEmpty(models)) {
            throw new PluginException("时间策略不存在，请先配置");
        }
        BmsTimeBillStrategyModel strategyModel = models.get(0);
        // 1.实际启运实际，2.实际到达实际 3.实际电子回单时间，4.实际正本回单时间
        int startDate = strategyModel.getStartDate();
        int endDate = strategyModel.getEndDate();
        Date startTime;
        Date endTime;
        // 开始时间
        if (startDate == 1) {
            startTime = costStrategy.getStartDate();
        }else if (startDate == 2){
            startTime = costStrategy.getDeliveryDate();
        } else if (startDate == 3) {
            startTime = costStrategy.getReceiptDate();
        } else {
            startTime = costStrategy.getOriginalBackDate();
        }
        // 结束时间
        if (endDate == 1) {
            endTime = costStrategy.getStartDate();
        }else if (endDate == 2){
            endTime = costStrategy.getDeliveryDate();
        } else if (endDate == 3) {
            endTime = costStrategy.getReceiptDate();
        } else {
            endTime = costStrategy.getOriginalBackDate();
        }

        long time1 = startTime.getTime();
        long time2 = endTime.getTime();

        BigDecimal minutes = BigDecimal.valueOf((time2 - time1) / 1000 / 60);

        Integer timeInteger = strategyModel.getTimeInteger();
        Integer timePrecision = strategyModel.getTimePrecision();

        // 获取小时
        if (timeInteger == 1) {
            minutes = minutes.divide(new BigDecimal(60),timePrecision, RoundingMode.HALF_UP);
        }
        // 向上取整
        if (timeInteger == 2) {
            minutes = minutes.divide(new BigDecimal(60),timePrecision, RoundingMode.UP);
        }
        // 向下取整
        if (timeInteger == 3) {
            minutes = minutes.divide(new BigDecimal(60),timePrecision, RoundingMode.DOWN);
        }
        // 启用阶梯时间换算
        if (strategyModel.getTimeLadderEnable().intValue() == 1) {
            Criteria criteriaLadder = Criteria.forClass(BmsTimeBillStrategyLadderModel.class);
            r2 = Restrictions.eq("timeStrategyId", strategyModel.getId());
            r3 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
            criteriaLadder.setRestriction(Restrictions.and( r2, r3));
            List<BmsTimeBillStrategyLadderModel> ladderModels = timeBillStrategyLadderMapper.findByCriteria(criteriaLadder);
            if (ObjectUtil.isEmpty(ladderModels)) {
                throw new PluginException("启用阶梯时间换算时,阶梯时间换算数据为空");
            }
            boolean flag = false;
            for (BmsTimeBillStrategyLadderModel ladderModel:ladderModels) {
                Boolean isMatch = matchTimeLadder(ladderModel,minutes);
                if (Boolean.TRUE.equals(isMatch)) {
                    minutes = ladderModel.getLadderTime();
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                throw new PluginException("启用阶梯时间换算时,没有匹配到阶梯时间换算数据");
            }
        }

        //return minutes.divide(new BigDecimal(60),2, RoundingMode.HALF_UP);
        return minutes;
    }

    private void saveFee(ShipBillPriceDTO dto,BmsShipBillHeaderModel costStrategy, BmsLogisticsContractModel contractModel, BmsFreightPriceModel priceModel, UserEntity user,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.setBillNo(costStrategy.getShipbillNo());
        feeDetailModel.setBillId(costStrategy.getId());
        feeDetailModel.setPayFeeType(1);
        feeDetailModel.setExpenseTypeName("运费");
        feeDetailModel.setTaxPoint(contractModel.getTaxPoint());
        feeDetailModel.setBillingSource(1);
        feeDetailModel.setBillingStatus(1);
        feeDetailModel.setBillingDate(DateUtil.date());
        feeDetailModel.setBillingContract(contractModel.getContractName());
        feeDetailModel.setBillingPrice(priceModel.getPriceName());
        //  费用编码、费用名称、费用科目名称、费用科目编码、费用类型 为价格表的费用反写（只有附加费才有）
        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) ? "收入" : "支出");
        }
        RestMessage<SySParameterDTO> parameterModel = maindataTmsResource.queryParameter();
        int taxPoint = Integer.parseInt(contractModel.getTaxPoint());
        if (ObjectUtil.isNotEmpty(parameterModel) && parameterModel.isSuccess()) {
            // 1：含税，2：未税
            Integer isTax = parameterModel.getData().getIsTax();
            // 含税金额 = 未税金额（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) {
                    totPrice = totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.HALF_UP);
                    feeDetailModel.setNoTaxAmt(totPrice.divide(point,costPrecision, RoundingMode.HALF_UP));
                }
                // 向上取整
                if (costInteger == 2) {
                    totPrice = totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP);
                    feeDetailModel.setNoTaxAmt(totPrice.divide(point,costPrecision, RoundingMode.UP));
                }
                // 向上取整
                if (costInteger == 3) {
                    totPrice = totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN);
                    feeDetailModel.setNoTaxAmt(totPrice.divide(point,costPrecision, RoundingMode.DOWN));
                }
                feeDetailModel.setTaxAmt(totPrice);
                feeDetailModel.setTax(totPrice.subtract(feeDetailModel.getNoTaxAmt()));
            } else {
                // 四舍五入
                if (costInteger == 1) {
                    totPrice = 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) {
                    totPrice = totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP);
                    feeDetailModel.setTaxAmt(totPrice.multiply(point).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.UP));
                }
                // 向上取整
                if (costInteger == 3) {
                    totPrice = totPrice.divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN);
                    feeDetailModel.setTaxAmt(totPrice.multiply(point).divide(BigDecimal.valueOf(1), costPrecision, RoundingMode.DOWN));
                }
                feeDetailModel.setNoTaxAmt(totPrice);
                feeDetailModel.setTax(feeDetailModel.getTaxAmt().subtract(feeDetailModel.getNoTaxAmt()));
            }
        }  else {
           throw new PluginException("获取系统参数异常");
        }
        feeDetailModel.setBillingType("");
        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 {
            // 类型为支出的含税金额
            // 通过费用科目编码 查询是否是支出的
//            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.isEmpty(mapper)) {
//                throw new PluginException("查询费用科目信息失败");
//            }
//            ExpenseAccountModel expenseAccountModel = mapper.get(0);
//            int expenseClassify = expenseAccountModel.getExpenseClassify();
//            if (expenseClassify == 2) {
//                dto.setPayAmount(dto.getPayAmount().add(feeDetailModel.getTaxAmt()));
//            }
//            // 类型为支出来源是价格表生成 含税金额
//            if (expenseClassify == 2 && feeDetailModel.getBillingSource().equals(1)) {
//                dto.setContractPayAmount(dto.getContractPayAmount().add(feeDetailModel.getTaxAmt()));
//            }

            bmsBillPayFeeDetailMapper.save(feeDetailModel);
        }
    }

    // 匹配时间阶梯
    public Boolean matchTimeLadder(BmsTimeBillStrategyLadderModel 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;
    }
}