package com.yem.wm.im.delivernotice.validator;

import com.yem.wm.es.Util.TotalUtil;
import com.yem.wm.es.shippingdetails.util.PaymentControlUtil;
import com.yem.wm.utils.YEM;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.entity.ExtendedDataEntity;
import kd.bos.entity.validate.AbstractValidator;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.BusinessDataServiceHelper;

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

/**
 * @author xwudd
 * @Description
 * @date 14:51
 **/
public class DeliverNoticeSubmitValidator extends AbstractValidator {
    @Override
    public void validate() {
        ExtendedDataEntity[] dataEntities = this.getDataEntities();
        for(ExtendedDataEntity dataEntitie : dataEntities){
//            arrearsAmtValidator(dataEntitie);
            if (specialApplicationShipment(dataEntitie)) continue;
            hasArrearsValidator(dataEntitie);
            creditInsuranceOverdueVerification(dataEntitie);
            isStorageTrans(dataEntitie);
            checkAmountAligned(dataEntitie);
        }
    }

    /**
     * 最后一笔出库的时候，判断出库金额是否和合同金额相等
     * @param dataEntitie
     */
    private void checkAmountAligned(ExtendedDataEntity dataEntitie) {
        DynamicObject dynamicObject = dataEntitie.getDataEntity();
        dynamicObject = BusinessDataServiceHelper.loadSingle(dynamicObject.getPkValue(), dynamicObject.getDynamicObjectType().getName());
        String salesorderno = dynamicObject.getString("yem_contractnum");
        DynamicObject single = BusinessDataServiceHelper.loadSingle("yem_es_salesorder", new QFilter[]{new QFilter("billno", QCP.equals, salesorderno)});
        if (single != null) {
            if (!isThisTheLastShipment(dynamicObject, single)) return;
            // 合同金额（价格条款）
            BigDecimal offeramount = BigDecimal.ZERO;
            DynamicObjectCollection salesorderEntry = single.getDynamicObjectCollection("yem_es_materialinfo");
            for (DynamicObject object : salesorderEntry) {
                BigDecimal saamtpriceclause = object.getBigDecimal("yem_saamtpriceclause");
                offeramount = offeramount.add(saamtpriceclause);
            }
            DynamicObject[] stackOut = PaymentControlUtil.getContractStockOut(single);
            List<DynamicObject> stacks = PaymentControlUtil.excludeThisShipment(stackOut, dynamicObject);
            BigDecimal historyAmount = BigDecimal.ZERO;
            for (DynamicObject stack : stacks) {
                BigDecimal totalallamount = stack.getBigDecimal("yem_totalallamount");
                historyAmount = historyAmount.add(totalallamount);
            }

            BigDecimal thisAmount = dynamicObject.getBigDecimal("yem_totalallamount");
            historyAmount = historyAmount.setScale(2, RoundingMode.HALF_UP);
            thisAmount = thisAmount.setScale(2, RoundingMode.HALF_UP);
            offeramount = offeramount.setScale(2, RoundingMode.HALF_UP);
            if (thisAmount.add(historyAmount).compareTo(offeramount) != 0) {
                this.addErrorMessage(dataEntitie, String.format("合同 [ %s ]下，当前出库金额 [ %s ] + 历史出库金额 [ %s ] 合计 [ %s ] 与合同金额 [ %s ] 相差 [ %s ]，请修改后提交！",
                        salesorderno,
                        thisAmount.setScale(2, RoundingMode.HALF_UP),
                        historyAmount.setScale(2, RoundingMode.HALF_UP),
                        thisAmount.add(historyAmount).setScale(2, RoundingMode.HALF_UP),
                        offeramount.setScale(2, RoundingMode.HALF_UP),
                        thisAmount.add(historyAmount).subtract(offeramount).setScale(2, RoundingMode.HALF_UP)
                ));
            }
        }
    }

    /**
     * 判断本次出库是否是最后一次出库
     *
     * @return
     */
    private boolean isThisTheLastShipment(DynamicObject stockOut, DynamicObject salesorder) {
        DynamicObjectCollection materialinfo = salesorder.getDynamicObjectCollection("yem_es_materialinfo");
        // 合同中分录行数量
        Map<Long, BigDecimal> salesorderQty = new HashMap<>();
        for (DynamicObject dynamicObject : materialinfo) {
            BigDecimal qty = dynamicObject.getBigDecimal("yem_qty");
            long id = dynamicObject.getLong("id");
            if (salesorderQty.containsKey(id)) {
                salesorderQty.put(id, salesorderQty.get(id).add(qty));
            } else {
                salesorderQty.put(id, qty);
            }
        }
        DynamicObject[] allStack = PaymentControlUtil.getContractStockOut(salesorder);
        List<DynamicObject> stacks = PaymentControlUtil.excludeThisShipment(allStack, stockOut);
        // 除去本次的已出库总数量总和(历史出库总和)
        Map<Long, BigDecimal> historyQty = new HashMap<>();
        for (DynamicObject stack : stacks) {
            DynamicObjectCollection entry = stack.getDynamicObjectCollection("yem_es_materialinfo");
            for (DynamicObject dynamicObject : entry) {
                long id = dynamicObject.getLong("yem_coreentryid");
                BigDecimal qty = dynamicObject.getBigDecimal("yem_qty");
                if (historyQty.containsKey(id)) {
                    historyQty.put(id, historyQty.get(id).add(qty));
                } else {
                    historyQty.put(id, qty);
                }
            }
        }
        DynamicObjectCollection thisTimeEntry = stockOut.getDynamicObjectCollection("yem_es_materialinfo");
        // 本次出库的数量
        Map<Long, BigDecimal> thisTimeEntryQty = new HashMap<>();
        for (DynamicObject dynamicObject : thisTimeEntry) {
            long id = dynamicObject.getLong("yem_coreentryid");
            BigDecimal qty = dynamicObject.getBigDecimal("yem_qty");
            if (thisTimeEntryQty.containsKey(id)) {
                thisTimeEntryQty.put(id, thisTimeEntryQty.get(id).add(qty));
            } else {
                thisTimeEntryQty.put(id, qty);
            }
        }
        // 扣减合同中的数量
        boolean pass = true;
        Set<Map.Entry<Long, BigDecimal>> entries = salesorderQty.entrySet();
        for (Map.Entry<Long, BigDecimal> entry : entries) {
            Long id = entry.getKey();
            if (historyQty.containsKey(id)) {
                salesorderQty.put(id, salesorderQty.get(id).subtract(historyQty.get(id)));
            }
            if (thisTimeEntryQty.containsKey(id)) {
                salesorderQty.put(id, salesorderQty.get(id).subtract(thisTimeEntryQty.get(id)));
            }
        }
        for (Map.Entry<Long, BigDecimal> entry : entries) {
            BigDecimal value = entry.getValue();
            if (value.compareTo(BigDecimal.ZERO) != 0) {
                pass = false;
            }
        }
        return pass;
    }

    /**
     * 校验当前客户是否有信保逾期
     * 信保限额申请单分录的应收款日期1小于当前时间并且有欠款金额
     * @param entry
     */
    private void creditInsuranceOverdueVerification(ExtendedDataEntity entry)
    {
        DynamicObject dataEntity = entry.getDataEntity();
        dataEntity = BusinessDataServiceHelper.loadSingle(dataEntity.getPkValue(), dataEntity.getDynamicObjectType().getName());
        DynamicObject customer = dataEntity.getDynamicObject("yem_customer");
        if (customer == null) return;
        long sourcebillid = dataEntity.getLong("yem_sourcebillid");
        DynamicObject shippingdetails = BusinessDataServiceHelper.loadSingle(sourcebillid, "yem_shippingdetails");
        if (shippingdetails == null) return;
        DynamicObject method = TotalUtil.getSettlementMethod(shippingdetails);
        DynamicObject company = dataEntity.getDynamicObject("yem_company.yem_erporg");
        String swiftCode = TotalUtil.getSwiftCode(shippingdetails);
        DynamicObject creditLine = TotalUtil.getCsrCreditLine(customer, method, company, swiftCode);
        if (creditLine == null) return;
        DynamicObjectCollection collection = creditLine.getDynamicObjectCollection("yem_im_info");
        for (DynamicObject dynamicObject : collection) {
            // 应收款日期1
            Date paydate = dynamicObject.getDate("yem_paydate1");
            BigDecimal amountowed = dynamicObject.getBigDecimal("yem_amountowed");
            Date now = new Date();
            if (paydate == null) continue;
            if (amountowed.compareTo(BigDecimal.ZERO) > 0 && paydate.before(now)) {
                this.addErrorMessage(entry, String.format("客户 %s 信保逾期，请确认！", customer.getString("name")));
            }
        }
    }


    /**
     * @description 发货通知单是否有欠款校验
     * @author xwudd
     * @param[1] dataEntitie
     * return
     * @time 2023/11/9 14:57
     */
    public void arrearsAmtValidator(ExtendedDataEntity dataEntitie){
        DynamicObject dataEntity = dataEntitie.getDataEntity();
        long id = dataEntity.getLong("id");
        String coreBillType = dataEntity.getString("yem_corebilltype");
        long coreBillId = dataEntity.getLong("yem_corebillid");
        if(YEM.isNotEmpty(coreBillType) && YEM.isNotEmpty(coreBillId)){
            DynamicObject saleOrder = BusinessDataServiceHelper.loadSingle(coreBillId,coreBillType);
            BigDecimal rapRate = PaymentControlUtil.getRapRate(saleOrder);
            BigDecimal collection = PaymentControlUtil.getCollection(coreBillId);//A 合同的所有收款
            BigDecimal contractPayment = PaymentControlUtil.getAdvancePayment(PaymentControlUtil.getContractPayment(saleOrder),rapRate);//B 合同的预收款
            BigDecimal deliverPayment = PaymentControlUtil.getBalancePayment(PaymentControlUtil.getDeliverPayment(id, coreBillType, coreBillId),rapRate);//C 提交、审核的历史发货尾款
            BigDecimal translateDeliverPayment = PaymentControlUtil.getBalancePayment(PaymentControlUtil.getTranslateDeliverPayment(dataEntity),rapRate);//D 本次发货尾款
            BigDecimal arrearsAmt = collection.subtract(contractPayment).subtract(deliverPayment).subtract(translateDeliverPayment).setScale(2, RoundingMode.HALF_UP);
            if(arrearsAmt.compareTo(BigDecimal.ZERO) < 0){
                BigDecimal fAbs = arrearsAmt.abs().setScale(2, RoundingMode.HALF_UP);
                this.addErrorMessage(dataEntitie,String.format("截止当前，本发货通知单存在欠款，欠款金额为%s，不允许提交，请收款齐全后重试！",fAbs));
            }
        }
    }


    /**
     * @description 判断发货行是否储运
     * @author xwudd
     * @param[1] dataEntitie
     * return
     * @time 2023/11/13 15:13
     */

    public void isStorageTrans(ExtendedDataEntity dataEntitie){
        DynamicObject dataEntity = dataEntitie.getDataEntity();
        List<Long> entryIds = new ArrayList();
        DynamicObjectCollection materialInfos = dataEntity.getDynamicObjectCollection("yem_es_materialinfo");
        for (int i = 0; i < materialInfos.size(); i++) {
            DynamicObject materialInfo = materialInfos.get(i);
            long sourceEntryId = materialInfo.getLong("yem_sourceentryid");
            entryIds.add(sourceEntryId);
        }

        Map<Long, Map<String,BigDecimal>> allMap = new HashMap<>();
        DynamicObject[] shippingDetails = BusinessDataServiceHelper.load("yem_shippingdetails", "yem_es_materialinfo.yem_storageqty,yem_es_materialinfo.yem_deliveryqty",
                new QFilter[]{new QFilter("yem_es_materialinfo.id", QCP.in, entryIds)});
        for(DynamicObject shippingDetail : shippingDetails){
            DynamicObjectCollection shippingMaterialInfos = shippingDetail.getDynamicObjectCollection("yem_es_materialinfo");
            for(DynamicObject shippingMaterialInfo : shippingMaterialInfos){
                long materialInfoId = shippingMaterialInfo.getLong("id");
                if(entryIds.contains(materialInfoId)){
                    HashMap<String, BigDecimal> map = new HashMap<>();
                    BigDecimal storageQty = shippingMaterialInfo.getBigDecimal("yem_storageqty");
                    BigDecimal deliveryQty = shippingMaterialInfo.getBigDecimal("yem_deliveryqty");
                    map.put("storageQty",storageQty);
                    map.put("deliveryQty",deliveryQty);
                    allMap.put(materialInfoId,map);
                }
            }
        }
        for (int i = 0; i < materialInfos.size(); i++) {
            DynamicObject materialInfo = materialInfos.get(i);
            long sourceEntryId = materialInfo.getLong("yem_sourceentryid");
            Map<String, BigDecimal> map = allMap.get(sourceEntryId);
            if(YEM.isNotEmpty(map)){
                BigDecimal storageQty = map.get("storageQty");
                BigDecimal deliveryQty = map.get("deliveryQty");
                if(deliveryQty.compareTo(storageQty) > 0){
                    this.addErrorMessage(dataEntitie,String.format("发货通知单明细信息第%s行还未进行储运，请下推订舱通知单后，在提交发货通知单！",i + 1));
                }
            }
        }
    }

    /**
     * 1、销售出库对应的合同（非本次发运明细单）--欠条是否有核销掉
     * @param dataEntities
     */
    private void hasArrearsValidator(ExtendedDataEntity dataEntities)
    {
        // 销售出库单
        DynamicObject dataEntity = dataEntities.getDataEntity();
        long shipDetailId = dataEntity.getLong("yem_sourcebillid");
        // 本次发运明细单
        DynamicObject shippingdetail = BusinessDataServiceHelper.loadSingle(shipDetailId, "yem_shippingdetails");
        if (shippingdetail == null) return;
        Long currShipId = (Long) shippingdetail.getPkValue();
        // 合同
        String contractnum = dataEntity.getString("yem_contractnum");
        DynamicObject saleOrder = BusinessDataServiceHelper.loadSingle("yem_es_salesorder", new QFilter[]{new QFilter("billno", QCP.equals, contractnum)});
        if (saleOrder == null) return;
        // 合同下所有的发运明细单
        long saleOrderId = saleOrder.getLong("id");
        DynamicObject[] load = BusinessDataServiceHelper.load("yem_shippingdetails", "id, billno", new QFilter[]{new QFilter("yem_corebillid", QCP.equals, saleOrderId)});
        // 去除本次的
        List<DynamicObject> exThis = new ArrayList<>();
        for (DynamicObject object : load) {
            Long pkValue = (Long) object.getPkValue();
            if (!pkValue.equals(currShipId)) {
                exThis.add(object);
            }
        }

        List<String> billno = new ArrayList<>();
        BigDecimal totalArrearsAmt = BigDecimal.ZERO;
        // 发运明细单下所有的欠条
        for (DynamicObject object : exThis) {
            DynamicObject[] iOUs = BusinessDataServiceHelper.load("yem_im_tradeapp", "id, billno, billstatus,yem_remainunwamount, yem_im_tradeapp_em.yem_shippingnumber", new QFilter[]{new QFilter("yem_im_tradeapp_em.yem_shippingnumber", QCP.equals, object.getString("billno")), new QFilter("billstatus", QCP.equals, "C")});
            for (DynamicObject dynamicObject : iOUs) {
                // 剩余未核销金额
                BigDecimal remainunwamount = dynamicObject.getBigDecimal("yem_remainunwamount");
                if (remainunwamount.compareTo(BigDecimal.ZERO) > 0) {
                    billno.add(dynamicObject.getString("billno"));
                    totalArrearsAmt = totalArrearsAmt.add(remainunwamount);
                }
            }
        }
        if (totalArrearsAmt.compareTo(BigDecimal.ZERO) > 0) {
            this.addErrorMessage(dataEntities, String.format("合同 %s 下还有未核销的欠条：%s，未核销金额为 %s，请核销后再提交！", contractnum, Arrays.toString(billno.toArray()),totalArrearsAmt.setScale(2, RoundingMode.HALF_UP)));
        }
    }

    /**
     * 销售出库提交时，如果有已审核的发货特殊申请，不需要校验是否信保预期，是否由未核销掉的欠条，否则需要核销；
     * @param dataEntitie
     * @return
     */
    private boolean specialApplicationShipment(ExtendedDataEntity dataEntitie) {
        DynamicObject dataEntity = dataEntitie.getDataEntity();
        Long pkValue = (Long) dataEntity.getPkValue();
        QFilter qFilter = new QFilter("yem_sourcebillid", QCP.equals, pkValue);
        qFilter.and(new QFilter("billstatus", QCP.equals, "C"));
        DynamicObject[] load = BusinessDataServiceHelper.load("yem_es_specialapplica", "id", qFilter.toArray());
        return load.length > 0;
    }
}
