package com.jwipc.contract.logic.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Pair;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.jwipc.constant.DelFlag;
import com.jwipc.contract.convert.ContractDeliveryConvert;
import com.jwipc.contract.convert.ContractDeliveryDetailConvert;
import com.jwipc.contract.dto.*;
import com.jwipc.contract.entity.ContractDelivery;
import com.jwipc.contract.entity.ContractDeliveryDetail;
import com.jwipc.contract.entity.ContractDetail;
import com.jwipc.contract.entity.ContractReturnOrderDetail;
import com.jwipc.contract.logic.ContractDeliveryLogic;
import com.jwipc.contract.logic.ContractLogic;
import com.jwipc.contract.model.query.ChoseSupplierListQuery;
import com.jwipc.contract.model.query.ContractDeliveryQuery;
import com.jwipc.contract.service.IContractDeliveryDetailService;
import com.jwipc.contract.service.IContractDeliveryService;
import com.jwipc.contract.service.IContractDetailService;
import com.jwipc.contract.service.IContractReturnOrderDetailService;
import com.jwipc.exception.DaoException;
import com.jwipc.page.PageUtil;
import com.jwipc.page.PageView;
import com.jwipc.security.LoginUtil;
import com.jwipc.sys.client.SequenceClient;
import com.jwipc.sys.constant.FinancialShareClient;
import com.jwipc.sys.dto.FinancialShareApiResultDTO;
import com.jwipc.sys.entity.BusinessAttachment;
import com.jwipc.sys.entity.FinancialShareContract;
import com.jwipc.sys.service.IBusinessAttachmentService;
import com.jwipc.sys.util.FinancialShareUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class ContractDeliveryLogicImpl implements ContractDeliveryLogic {

    private final ContractDeliveryConvert contractDeliveryConvert;
    private final ContractDeliveryDetailConvert contractDeliveryDetailConvert;

    private final static String  CONTRACT_DELIVERY = " ContractDeliveryLock_";
    private final StringRedisTemplate redisTemplate;
    private final IContractDeliveryService contractDeliveryService;
    private final IContractDeliveryDetailService contractDeliveryDetailService;
    private final IContractReturnOrderDetailService contractReturnOrderDetailService;
    private final SequenceClient sequenceClient;
    private final FinancialShareUtil financialShareUtil;
    private final FinancialShareClient financialShareClient;
    private final IBusinessAttachmentService businessAttachmentService;
    private final IContractDetailService contractDetailService;
    /**
     * 保存收货单
     * @param deliveryOrderSaveDTO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Pair<String, Set<String>> saveOrUpdate(ContractDeliverySaveDTO deliveryOrderSaveDTO) {
        final String lockKey = CONTRACT_DELIVERY + LoginUtil.getUserId();
        if (!redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS)) {
            log.info("系统正在处理，请稍后");
            throw new DaoException("系统正在处理，请稍后提交!");
        }

        //需要保存收货单信息
        ContractDelivery deliveryOrder = contractDeliveryConvert.dto2Entity(deliveryOrderSaveDTO);
        List<ContractDeliveryDetailSaveDTO> item = deliveryOrderSaveDTO.getItem();
        if (CollectionUtils.isEmpty(item)) {
            throw new DaoException("没有送货单明细行");
        }
        //查询统计 送货数量，可送数量，未清数量实时数量进行校验
        //根据合同编号 + 合同序号统计出实时可送数量后，与收货数量进行对比后，收货数量只能小于等于实时可送货数量
        //增加送货单订单+行号重复校验
        List<String> dataKeys = item.stream().map(d -> d.getContractNo() + "_" + d.getContractSeq()).distinct().collect(Collectors.toList());
        ContractOrderQuantityDTO contactOrderNumData = findContactOrderNumData(dataKeys);
        Map<String, BigDecimal> returntMap = contactOrderNumData.getReturntMap();//订单行退货数量
        Map<String, BigDecimal> onlineNumMap = contactOrderNumData.getOnlineNumMap();//订单行在途送货数量
        Map<String, BigDecimal> receiveNumMap = contactOrderNumData.getReceiveNumMap();//订单行已收货数量
        //进行订单收货单几种类型数量校验(收货数量不能大于订单数据)


        //增加校验是否有重复的check
        Map<String, Integer> checkMap = new HashMap<>();
        for (ContractDeliveryDetailSaveDTO orderDetail : item) {
            String dataKey = orderDetail.getContractNo()+"_"+orderDetail.getContractSeq();
            BigDecimal orderNum = orderDetail.getOrderQuantity();
            BigDecimal returntNum = returntMap.get(dataKey); //退货数量
            BigDecimal onlineNum = onlineNumMap.get(dataKey);//在途收货数量
            BigDecimal receiveNum = receiveNumMap.get(dataKey);//已收货数量
            BigDecimal deliverableNum = orderNum.subtract(onlineNum == null ? BigDecimal.ZERO:onlineNum).subtract(receiveNum== null ? BigDecimal.ZERO:receiveNum).add(returntNum == null ? BigDecimal.ZERO:returntNum);
            //对比可送数量与送货数量
            if(orderDetail.getReceivedQuantity().compareTo(deliverableNum) > 0){
                throw new DaoException("收货单合同编号："+orderDetail.getContractNo() +"合同序号："+orderDetail.getContractSeq()+"填写的收货数量不能大于实际可送数量");
            }
            //对比订单数量和送货数量+在途数量+退货数量
            if(orderNum.compareTo((onlineNum == null ? BigDecimal.ZERO:onlineNum).add(receiveNum== null ? BigDecimal.ZERO:receiveNum).add(orderDetail.getReceivedQuantity() == null ? BigDecimal.ZERO:orderDetail.getReceivedQuantity()).subtract((returntNum == null ? BigDecimal.ZERO: returntNum))) < 0){
                throw new DaoException("收货单合同编号："+orderDetail.getContractNo() +"合同序号："+orderDetail.getContractSeq()+"填写的收货数量+已收货数量+在途数量+退货数量不能大于订单数量");
            }

            String contractNo = orderDetail.getContractNo();
            String contractRow = orderDetail.getReceiptLineNo();
            String key = contractNo+":"+contractRow;
            if( checkMap.get(key) == null){
                checkMap.put(key,1);
            }else{
                checkMap.put(key,checkMap.get(key) + 1);
            }
        }
        int rowNo = 0;
        for (ContractDeliveryDetailSaveDTO orderDetail : item) {
            String contractNo = orderDetail.getContractNo();
            String contractRow = orderDetail.getReceiptLineNo();
            String key = contractNo+":"+contractRow;
//            if(checkMap.get(key) > 1){
//                final String format = StrUtil.format("创建合同收货单失败:{}-{},合同编号和合同行号重复", contractNo,
//                        contractRow);
//                throw new DaoException(format);
//            }
            rowNo++;
            orderDetail.setReceiptLineNo(String.valueOf(rowNo));
        }
        String deliveryNo = deliveryOrder.getDeliveryNo();
        List<ContractDeliveryDetail> contractDeliveryDetails = contractDeliveryDetailConvert.dtos2Entities(item);
        Set<String> msg = Sets.newHashSet();
        //保存合同主表操作
        if(deliveryOrder.getId() == null){ //新增
            deliveryNo = sequenceClient. getBarCodeSequenceNo("contract_delivery", 8,false);
            deliveryOrder.setDeliveryNo(deliveryNo);
        }
        deliveryOrder.setCreateId(LoginUtil.getUserId());
        deliveryOrder.setCreateTime(LocalDateTime.now());
        deliveryOrder.setDeleteFlag(0);
        deliveryOrder.setDeliveryStatus(1);
        deliveryOrder.setDocumentType("01");
        if(contractDeliveryService.saveOrUpdate(deliveryOrder)){
            String finalDeliveryNo = deliveryNo;
            contractDeliveryDetails.stream()
                    .forEach(detail -> {
                        detail.setDeliveryNo(finalDeliveryNo);
                        detail.setDeliveryId(deliveryOrder.getId());
                        detail.setDeleteFlag(0);
                        detail.setCreateId(LoginUtil.getUserId());
                        detail.setCreateTime(LocalDateTime.now());
                    });
            contractDeliveryDetailService.saveBatch(contractDeliveryDetails);
            msg.add("创建成功");
        }
        Set<Long> ids = Sets.newHashSet();
        return Pair.of(ids.stream().map(String::valueOf).collect(Collectors.joining(",")), msg);
    }

    private JSONObject postGxReceiptBill(ContractDelivery deliveryOrder,List<ContractDeliveryDetail> contractDeliveryDetails){
        String shareAccessToken = financialShareUtil.getShareAccessToken();
        JSONObject mainObj = new JSONObject(); // 创建最外层JSON对象
        JSONArray dataArray = new JSONArray();// 创建data数组
        // 创建单个data对象
        JSONObject dataObj = new JSONObject();
        dataObj.put("billno", deliveryOrder.getDeliveryNo());
        dataObj.put("m4p4_billtype", "01");//送货类型
        dataObj.put("m4p4_receipt_date",deliveryOrder.getDeliveryDate());
        dataObj.put("m4p4_receipt_status", "01");//单据状态收货状态
        dataObj.put("org_number",deliveryOrder.getPurchaserCode());//购货方.编码
        dataObj.put("m4p4_supplier_number", deliveryOrder.getSupplierCode());//供应商.编码
        dataObj.put("m4p4_consignee_number", deliveryOrder.getReceiver());//receiver
        // 创建receipt_entry数组
        JSONArray receiptEntryArray = new JSONArray();
        for (ContractDeliveryDetail detail : contractDeliveryDetails) {
            // 创建单个receipt_entry对象
            JSONObject receiptEntryObj = new JSONObject();
            receiptEntryObj.put("m4p4_contract_no", detail.getContractNo());//收货明细.合同编号
            receiptEntryObj.put("m4p4_contract_num", detail.getContractSeq());//收货明细.合同序号
            receiptEntryObj.put("m4p4_item_name", detail.getItemName());//收货明细.物品名称
            receiptEntryObj.put("m4p4_model_params", detail.getModelSpec());//收货明细.型号规格/参数
            receiptEntryObj.put("m4p4_brand", detail.getBrand());//收货明细.品牌
            receiptEntryObj.put("m4p4_requisition_no", detail.getRequisitionNo());//收货明细.请购单编号
            receiptEntryObj.put("m4p4_order_quantity", detail.getOrderQuantity());//收货明细.订单数量
            receiptEntryObj.put("m4p4_receipt_quantity", detail.getReceivedQuantity());//收货明细.收货数量
            receiptEntryObj.put("m4p4_device_serial_no", StringUtils.isEmpty(detail.getDeviceSerialNo()) ? "1" : detail.getDeviceSerialNo() );//收货明细.设备序列号
            receiptEntryObj.put("m4p4_asset_class_number",detail.getAssetCategory());//detail.getAssetCategory());//资产类别.编码
            receiptEntryObj.put("m4p4_unit_number",detail.getUnit());//单位.编码
            receiptEntryObj.put("m4p4_requisition_org_number",detail.getRequisitionDept());//detail.getRequisitionDept() );//请购部门.编码
            receiptEntryObj.put("m4p4_cost_center_number",detail.getCostCenter());//detail.getCostCenter());//成本中心.编码
            receiptEntryObj.put("m4p4_storage_location_number", detail.getStorageLocation());//存放地点.编码
            receiptEntryObj.put("seq",detail.getReceiptLineNo());//收货明细.分录行号
            receiptEntryObj.put("m4p4_unit_price",detail.getNoTaxPrice() );//未税单价
            receiptEntryObj.put("m4p4_unit_price_tax",detail.getPrice());//含税单价
            receiptEntryObj.put("m4p4_custodian_number",detail.getUserCode());//含税单价
            receiptEntryArray.add(receiptEntryObj);
        }
        dataObj.put("m4p4_receipt_entry", receiptEntryArray);
        dataArray.add(dataObj);
        mainObj.put("data", dataArray);
        log.info("合同收货单推送共享创建单据入参："+mainObj.toJSONString());
        FinancialShareApiResultDTO contractDelivery = financialShareClient.createContractDelivery(shareAccessToken, mainObj);
        JSONObject data = financialShareUtil.handleApiResult(contractDelivery, "创建创建合同收货单申请单");
        JSONArray resultArray = data.getJSONArray("result");
        JSONObject jsonObject = resultArray.getJSONObject(0);
        return jsonObject;
    }


    @Override
    public PageView getList(ContractDeliveryQuery query) {
        Page<ContractDelivery> page = PageUtil.toPage(query);
        List<ContractDelivery> list = contractDeliveryService.findList(page, query);
        List<ContractDeliveryDTO> dtos = contractDeliveryConvert.entities2Dtos(list);
        final Set<Long> ids = dtos.stream().map(ContractDeliveryDTO::getId).collect(Collectors.toSet());
        if (CollUtil.isNotEmpty(ids)) {
            final List<BusinessAttachment> businessAttachmentList = businessAttachmentService.list(new LambdaQueryWrapper<BusinessAttachment>()
                    .in(BusinessAttachment::getBusinessId, ids).eq(BusinessAttachment::getBusinessTypeCode, "contract_delivery"));
            final Map<Long, List<Long>> businessAttachmentMap = businessAttachmentList.stream().collect(
                    Collectors.groupingBy(BusinessAttachment::getBusinessId,
                            Collectors.mapping(BusinessAttachment::getFileId, Collectors.toList())));
            for (ContractDeliveryDTO dto : dtos) {
                if (Objects.nonNull(businessAttachmentMap.get(dto.getId()))) {
                    dto.setAttachmentFiles("1");
                }
            }
        }

        return PageUtil.getPV(dtos, page.getTotal());
    }

    @Override
    public ContractDeliveryLookupDTO getDeliveryById(Long id) {
        ContractDelivery delivery = contractDeliveryService.getById(id);
        ContractDeliveryLookupDTO dto = contractDeliveryConvert.entity2LookupDTO(delivery);
        return dto;
    }

    @Override
    public ContractDeliveryLookupDTO createDelivery() {
        String deliveryNo = sequenceClient. getBarCodeSequenceNo("contract_delivery", 8,false);
        ContractDelivery deliveryOrder = new ContractDelivery();
        deliveryOrder.setDeliveryNo(deliveryNo);
        deliveryOrder.setDeleteFlag(0);
        deliveryOrder.setDeliveryStatus(1);
        deliveryOrder.setReceiver(LoginUtil.getAccount());
        deliveryOrder.setCreateId(LoginUtil.getUserId());
        deliveryOrder.setCreateTime(LocalDateTime.now());
        deliveryOrder.setDeliveryDate(LocalDate.now());
        deliveryOrder.setDocumentType("01");
        contractDeliveryService.saveOrUpdate(deliveryOrder);
        return contractDeliveryConvert.entity2LookupDTO(deliveryOrder);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ContractDeliverySaveDTO dto) {
        ContractDelivery contractDelivery = contractDeliveryConvert.dto2Entity(dto);
        contractDelivery.setUpdateId(LoginUtil.getUserId());
        contractDelivery.setUpdateTime(LocalDateTime.now());
        contractDeliveryService.updateById(contractDelivery);
        final List<ContractDeliveryDetailSaveDTO> item = dto.getItem();
        List<ContractDeliveryDetail> updateLists = Lists.newArrayList();
        List<String> dataKeys = item.stream()
                .map(d -> d.getContractNo() + "_" + d.getContractSeq())
                .distinct()
                .collect(Collectors.toList());
        if(CollUtil.isNotEmpty(dataKeys)){
            ContractOrderQuantityDTO contactOrderNumData = findContactOrderNumData(dataKeys);
            Map<String, BigDecimal> returntMap = contactOrderNumData.getReturntMap();//订单行退货数量
            Map<String, BigDecimal> onlineNumMap = contactOrderNumData.getOnlineNumMap();//订单行在途送货数量
            Map<String, BigDecimal> receiveNumMap = contactOrderNumData.getReceiveNumMap();//订单行已收货数量
            if (CollUtil.isNotEmpty(item)) {
                //计算收货，退货数量情况，进行校验逻辑
                for (ContractDeliveryDetailSaveDTO saveDTO : item) {
                    String dataKey = saveDTO.getContractNo()+"_"+saveDTO.getContractSeq();
                    BigDecimal orderNum = saveDTO.getOrderQuantity();
                    BigDecimal returntNum = returntMap.get(dataKey);
                    BigDecimal onlineNum = onlineNumMap.get(dataKey);
                    BigDecimal receiveNum = receiveNumMap.get(dataKey);
                    BigDecimal deliverableNum = orderNum.subtract(onlineNum == null ? BigDecimal.ZERO.stripTrailingZeros():onlineNum).subtract(receiveNum== null ? BigDecimal.ZERO.stripTrailingZeros():receiveNum).add(returntNum == null ? BigDecimal.ZERO.stripTrailingZeros():returntNum);
                    if(saveDTO.getReceivedQuantity().compareTo(deliverableNum) > 0){
                        throw new DaoException("收货单合同编号："+saveDTO.getContractNo() +"合同序号："+saveDTO.getContractSeq()+"填写的收货数量不能大于实际可送数量");
                    }
                    saveDTO.setUpdateTime(LocalDateTime.now());
                    saveDTO.setUpdateId(LoginUtil.getUserId());
                    ContractDeliveryDetail detail = contractDeliveryDetailConvert.dto2Entity(saveDTO);
                    updateLists.add(detail);
                }
                contractDeliveryDetailService.updateBatchById(updateLists);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmReceipt(Long id) {
        ContractDelivery contractDelivery = new ContractDelivery();
        contractDelivery.setId(id);
        contractDelivery.setDeliveryStatus(2);
        contractDelivery.setUpdateTime(LocalDateTime.now());
        contractDelivery.setUpdateId(LoginUtil.getUserId());
        contractDeliveryService.updateById(contractDelivery);
        ContractDelivery delivery = contractDeliveryService.getById(id);
        //查询收货单主表数据及收货单明细表，调用共享接口
        if(delivery != null){
            List<ContractDeliveryDetail> list = contractDeliveryDetailService.list(new LambdaQueryWrapper<ContractDeliveryDetail>().eq(ContractDeliveryDetail::getDeliveryId, id));
            if(!CollectionUtils.isEmpty(list)){
                //查询收货单主表数据及收货单明细表，调用共享接口
                JSONObject jsonObject = postGxReceiptBill(delivery, list);
                LambdaUpdateWrapper<ContractDelivery> update = new LambdaUpdateWrapper<ContractDelivery>()
                        .set(ContractDelivery::getSyncGxNo,jsonObject.getString("number"))
                        .set(ContractDelivery::getSyncGxId,jsonObject.getString("id"))
                        .set(ContractDelivery::getSyncState,0)
                        .eq(ContractDelivery::getId,id);
                contractDeliveryService.update(update);
            }
        }
    }

    @Override
    public void deliveryRemove(Long id) {
        ContractDelivery contractDelivery = new ContractDelivery();
        contractDelivery.setId(id);
        contractDelivery.setDeleteFlag(1);
        contractDelivery.setUpdateTime(LocalDateTime.now());
        contractDelivery.setUpdateId(LoginUtil.getUserId());
        contractDeliveryService.updateById(contractDelivery);
        contractDeliveryDetailService.update(
                new LambdaUpdateWrapper<ContractDeliveryDetail>().set(ContractDeliveryDetail::getDeleteFlag,
                        DelFlag.DELETE.getStatus())
                        .set(ContractDeliveryDetail::getUpdateTime,LocalDateTime.now())
                        .set(ContractDeliveryDetail::getUpdateId,LoginUtil.getUserId())
                        .eq(ContractDeliveryDetail::getDeliveryId, id));
    }
    @Override
    public ContractOrderQuantityDTO findContactOrderNumData(List<String> dataKes){
        ContractOrderQuantityDTO dto = new ContractOrderQuantityDTO();
        List<ContractDeliveryDetail>  deliveryDetails =  contractDeliveryDetailService.selectSumReivedQuantity(dataKes);
        List<ContractReturnOrderDetail> returnOrderDetails = contractReturnOrderDetailService.selectSumReturnQuantity(dataKes);
        Map<String, BigDecimal> onlineNumMap = new HashMap<>();
        if(!CollectionUtils.isEmpty(deliveryDetails)){
            onlineNumMap = deliveryDetails.stream()
                    .collect(Collectors.toMap(
                            detail -> detail.getContractNo() + "_" + detail.getContractSeq(),
                            ContractDeliveryDetail::getOnlineNum,
                            (oldValue, newValue) -> oldValue
                    ));
        }
        Map<String, BigDecimal> receiveNumMap = new HashMap<>();
        if(!CollectionUtils.isEmpty(deliveryDetails)){
            receiveNumMap = deliveryDetails.stream()
                    .collect(Collectors.toMap(
                            detail -> detail.getContractNo() + "_" + detail.getContractSeq(),
                            ContractDeliveryDetail::getReceiveNum,
                            (oldValue, newValue) -> oldValue
                    ));
        }
        Map<String, BigDecimal> returntMap = new HashMap<>();
        if(!CollectionUtils.isEmpty(returnOrderDetails)){
            returntMap = returnOrderDetails.stream()
                    .collect(Collectors.toMap(
                            detail -> detail.getContractNo() + "_" + detail.getContractSeq(),
                            ContractReturnOrderDetail::getReturnQuantity,
                            (oldValue, newValue) -> oldValue
                    ));
        }
        dto.setReceiveNumMap(receiveNumMap);
        dto.setOnlineNumMap(onlineNumMap);
        dto.setReturntMap(returntMap);
        return dto;
    }

    @Override
    public void contractDeliveryImport(MultipartFile file) {
        List<ContractDeliveryImportSaveDTO> cachedDataList = ListUtils.newArrayList();
        //进行数据文件转换
        try {
            EasyExcel.read(file.getInputStream(), ContractDeliveryImportSaveDTO.class,
                    new ReadListener<ContractDeliveryImportSaveDTO>() {
                        @Override
                        public void invoke(ContractDeliveryImportSaveDTO data, AnalysisContext context) {
                            if (Strings.isNullOrEmpty(data.getContractNo())) {
                                throw new DaoException("合同编号不能为空!");
                            }
                            if (Strings.isNullOrEmpty(data.getContractSeq())) {
                                throw new DaoException("合同序号不能为空!");
                            }
                            String codeDateStr = data.getDeliveryDateStr();//收货日期字符串格式
                            try {
                                codeDateStr = codeDateStr.replaceAll("/", "-");
                                Date codeDate = DateUtil.parse(codeDateStr, "yyyy-MM-dd");
                                data.setDeliveryDate(LocalDateTimeUtil.parse(DateUtil.format(codeDate, "yyyy-MM-dd"), "yyyy-MM-dd"));
                            } catch (Exception e) {
                                throw new DaoException("请输入正确的收货日期格式；如：2025-11-11");
                            }
                            if (Strings.isNullOrEmpty(data.getRequisitionNo())) {
                                throw new DaoException("请购单编号不能为空!");
                            }
                            if (Strings.isNullOrEmpty(data.getItemCode())) {
                                throw new DaoException("请购单行号不能为空!");
                            }

                            if (null == data.getReceivedQuantity()) {
                                throw new DaoException("数量不能为空!");
                            }
                            if (null == data.getReceiver()) {
                                throw new DaoException("收货人工号不能为空!");
                            }
                            if (Strings.isNullOrEmpty(data.getPurchaser())) {
                                throw new DaoException("甲方名称不能为空!");
                            }
                            if (Strings.isNullOrEmpty(data.getPurchaserCode())) {
                                throw new DaoException("甲方代码不能为空!");
                            }
                            if (Strings.isNullOrEmpty(data.getSupplier())) {
                                throw new DaoException("乙方名称不能为空!");
                            }
                            if (Strings.isNullOrEmpty(data.getSupplierCode())) {
                                throw new DaoException("乙方代码不能为空!");
                            }
                            cachedDataList.add(data);
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                        }
                    }).sheet().doRead();
        } catch (IOException e) {
            throw new DaoException("导入失败！");
        }
        //判断甲方乙方给是不是同一个
        checkPurchaserAndSupplier(cachedDataList);
        //进行数据查询任务
        // 通过合同编号，合同行号查询数据
        ChoseSupplierListQuery query = new ChoseSupplierListQuery();
        List<String> contractCodeAndlineNos = getContractCodeAndlineNos(cachedDataList);
        List<String> purchaseCodeItemCodes = getPurchaseCodeItemCodes(cachedDataList);
        if (CollectionUtils.isEmpty(contractCodeAndlineNos)) {
            throw new DaoException("批量导入数据合同编号和合同行号不能为空!");
        }
        query.setContractCodeAndlineNos(contractCodeAndlineNos);
        query.setPurchaseCodeItemCodes(purchaseCodeItemCodes);
        List<ContractDetail> contractDetails = selectReceiptContractDetailList(query);
        List<ContractDeliveryDetail> contractDeliveryDetails = new ArrayList<>();
        //进行保存数据操作
        if (!CollectionUtils.isEmpty(contractDetails)) {
            Map<String, ContractDetail> map = new HashMap<>();
            //进行填写的送货数量和未清数量进行比较，如果送货数量大于未清数量，则报错提示
            for (ContractDetail contractDetail : contractDetails) {
                String key = contractDetail.getContractCode() + "_" + contractDetail.getLineNo();
                map.put(key, contractDetail);
            }
            for (ContractDeliveryImportSaveDTO importSaveDTO : cachedDataList) {
                String key = importSaveDTO.getContractNo() + "_" + importSaveDTO.getContractSeq();
                ContractDetail matchingDetail = map.get(key);
                //进行赋值操作
                if (matchingDetail != null) {
                    //保存时校验数据失败直接终止保存，提示错误信息到前台
                    if (importSaveDTO.getReceivedQuantity().compareTo(matchingDetail.getUnclearNum()) > 0) {
                        throw new DaoException("批量导入数据合同编号：" + importSaveDTO.getContractNo() + "，合同行号" + importSaveDTO.getContractSeq() + ",送货数量不能大于未清数量！");
                    }
                }
            }
            //保存成功则提示创建成功
            final String lockKey = CONTRACT_DELIVERY + LoginUtil.getUserId();
            if (!redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS)) {
                log.info("系统正在处理，请稍后");
                throw new DaoException("系统正在处理，请稍后提交!");
            }
            String deliveryNo = sequenceClient.getBarCodeSequenceNo("contract_delivery", 8, false);

            //组装保存头信息
            ContractDelivery deliveryOrder = new ContractDelivery();
            deliveryOrder.setDeliveryNo(deliveryNo);//收货单号
            deliveryOrder.setReceiver(cachedDataList.get(0).getReceiver());//收货人
            deliveryOrder.setDeliveryDate(cachedDataList.get(0).getDeliveryDate().toLocalDate());//收货日期
            deliveryOrder.setDocumentType("01");//收货
            deliveryOrder.setPurchaser(cachedDataList.get(0).getPurchaser());//购货方
            deliveryOrder.setSupplier(cachedDataList.get(0).getSupplier());//送货方
            deliveryOrder.setPurchaserCode(cachedDataList.get(0).getPurchaserCode());//甲方代码;
            deliveryOrder.setSupplierCode(cachedDataList.get(0).getSupplierCode());//供应商代码
            deliveryOrder.setDeleteFlag(0);
            deliveryOrder.setDeliveryStatus(1);
            deliveryOrder.setCreateId(LoginUtil.getUserId());
            deliveryOrder.setCreateTime(LocalDateTime.now());
            contractDeliveryService.saveOrUpdate(deliveryOrder);
            //组装保存明细数据
            int rowNo = 0;
            for (ContractDeliveryImportSaveDTO importSaveDTO : cachedDataList) {
                String key = importSaveDTO.getContractNo() + "_" + importSaveDTO.getContractSeq();
                ContractDetail matchingDetail = map.get(key);
                //进行赋值操作
                if (matchingDetail != null) {
                    ContractDeliveryDetail deliveryDetail = new ContractDeliveryDetail();
                    deliveryDetail.setReceiptLineNo(String.valueOf(rowNo));
                    deliveryDetail.setContractNo(matchingDetail.getContractCode());
                    deliveryDetail.setContractSeq(String.valueOf(matchingDetail.getLineNo()));
                    deliveryDetail.setAssetCategory(matchingDetail.getSubjectCode());
                    deliveryDetail.setItemName(matchingDetail.getMaterialName());
                    deliveryDetail.setModelSpec(matchingDetail.getMaterialSpec());
                    deliveryDetail.setBrand(matchingDetail.getMaterialBrand());
                    deliveryDetail.setRequisitionNo(matchingDetail.getPurchaseCode());
                    deliveryDetail.setUnit(matchingDetail.getBasisUnit());
                    deliveryDetail.setOrderQuantity(matchingDetail.getNum());
                    deliveryDetail.setReceivedQuantity(importSaveDTO.getReceivedQuantity());
                    deliveryDetail.setRequisitionDept(matchingDetail.getUserCode());
                    deliveryDetail.setCustodian(matchingDetail.getUserCode());
                    deliveryDetail.setCostCenter(matchingDetail.getCostCenterCode());
                    deliveryDetail.setStorageLocation(matchingDetail.getStockPoint());
                    deliveryDetail.setAssetPurpose(matchingDetail.getMainUses());
                    deliveryDetail.setAssetCondition(matchingDetail.getMainUses());
                    deliveryDetail.setDeliveryNo(deliveryNo);
                    deliveryDetail.setRequisitionItem(matchingDetail.getItemCode());
                    deliveryDetail.setDeleteFlag(0);
                    deliveryDetail.setCreateId(LoginUtil.getUserId());
                    deliveryDetail.setCreateTime(LocalDateTime.now());
                    deliveryDetail.setDeliveryId(deliveryOrder.getId());
                    deliveryDetail.setUseDeptName(matchingDetail.getUseDeptName());
                    deliveryDetail.setUserCode(matchingDetail.getUserCode());
                    deliveryDetail.setNoTaxPrice(matchingDetail.getNoTaxPrice());
                    deliveryDetail.setPrice(matchingDetail.getPrice());
                    deliveryDetail.setItemCode(matchingDetail.getItemCode());
                    contractDeliveryDetails.add(deliveryDetail);
                    rowNo++;
                }
            }
            if (!CollectionUtils.isEmpty(contractDeliveryDetails)) {
                contractDeliveryDetailService.saveBatch(contractDeliveryDetails);
            }
        }


    }

    @Override
    public void blankDeliveryRemove(Long id) {
        contractDeliveryService.remove( new LambdaUpdateWrapper<ContractDelivery>().eq(ContractDelivery::getId,id).isNull(ContractDelivery::getPurchaserCode));

    }

    private void checkPurchaserAndSupplier(List<ContractDeliveryImportSaveDTO> cachedDataList) {
        if (CollectionUtils.isEmpty(cachedDataList)) {
            return;
        }

        // 判断购货方是否一致
        long purchaserCount = cachedDataList.stream()
                .map(ContractDeliveryImportSaveDTO::getPurchaserCode)
                .filter(Objects::nonNull)
                .distinct()
                .count();

        if (purchaserCount > 1) {
            throw new DaoException("请选择相同的甲方代码");
        }

        // 判断供应商是否一致
        long supplierCount = cachedDataList.stream()
                .map(ContractDeliveryImportSaveDTO::getSupplierCode)
                .filter(Objects::nonNull)
                .distinct()
                .count();

        if (supplierCount > 1) {
            throw new DaoException("请选择相同的乙方代码");
        }

        long purchaserNameCount = cachedDataList.stream()
                .map(ContractDeliveryImportSaveDTO::getPurchaser)
                .filter(Objects::nonNull)
                .distinct()
                .count();
        if (purchaserNameCount > 1) {
            throw new DaoException("请选择相同的甲方名称");
        }
        long supplierNameCount = cachedDataList.stream()
                .map(ContractDeliveryImportSaveDTO::getSupplier)
                .filter(Objects::nonNull)
                .distinct()
                .count();
        if (supplierNameCount > 1) {
            throw new DaoException("请选择相同的乙方名称");
        }
    }


    public List<String> getContractCodeAndlineNos(List<ContractDeliveryImportSaveDTO> cachedDataList) {
        return cachedDataList.stream()
                .map(dto -> dto.getContractNo() + "_" + dto.getContractSeq())
                .collect(Collectors.toList());
    }

    public List<String> getPurchaseCodeItemCodes(List<ContractDeliveryImportSaveDTO> cachedDataList) {
        return cachedDataList.stream()
                .map(dto -> dto.getRequisitionNo() + "_" + dto.getItemCode())
                .collect(Collectors.toList());
    }

    public List<ContractDetail> selectReceiptContractDetailList(ChoseSupplierListQuery query) {
        //查询合同信息不需要分页
        List<ContractDetail> details =  contractDetailService.selectReceiptContractDetailList(query);
        if(!CollectionUtils.isEmpty(details)){
            //进行金额计算，将不符合的数据进行导入页面提示
            List<String> dataKeys = details.stream()
                    .map(d -> d.getContractCode() + "_" + d.getLineNo())
                    .distinct()
                    .collect(Collectors.toList());
            ContractOrderQuantityDTO contactOrderNumData = this.findContactOrderNumData(dataKeys);
            Map<String, BigDecimal> onlineNumMap = contactOrderNumData.getOnlineNumMap();
            Map<String, BigDecimal> receiveNumMap = contactOrderNumData.getReceiveNumMap();
            Map<String, BigDecimal> returntMap = contactOrderNumData.getReturntMap();
            for (ContractDetail detail : details) {
                //收货数量大于未清数量就要给出错误提示
                String key = detail.getContractCode()+"_"+detail.getLineNo();
                BigDecimal onlineNum  = onlineNumMap.get(key) == null ? BigDecimal.ZERO.stripTrailingZeros() :  onlineNumMap.get(key);
                BigDecimal receiveNum = receiveNumMap.get(key) == null ? BigDecimal.ZERO.stripTrailingZeros() : receiveNumMap.get(key) ;
                BigDecimal  returnNum = returntMap.get(key) == null ? BigDecimal.ZERO.stripTrailingZeros() : returntMap.get(key);
                //未清数量
                BigDecimal unclearNum  = detail.getNum().subtract(onlineNum).subtract(receiveNum).add(returnNum);
                //可送数量
                BigDecimal  deliverableNum  = unclearNum;
                //收货数量
                BigDecimal shipmentNum = deliverableNum ;
                detail.setOnlineNum(onlineNum);
                detail.setReceiveNum(receiveNum);
                detail.setReturnNum(returnNum);
                detail.setUnclearNum(unclearNum);
                detail.setDeliverableNum(deliverableNum);
                detail.setShipmentNum(shipmentNum);
            }

        }
        return details;
    }

    public static void main(String[] args) {
        JSONObject mainObj = new JSONObject();

        // 创建data数组
        JSONArray dataArray = new JSONArray();
        // 创建单个data对象
        JSONObject dataObj = new JSONObject();
        dataObj.put("billno", "SHD-20251213-0001");
        dataObj.put("m4p4_billtype", "01");
        dataObj.put("m4p4_receipt_date", "2025-12-13 11:20:45");
        dataObj.put("m4p4_receipt_status", "01");
        dataObj.put("org_number", "1000");
        dataObj.put("m4p4_supplier_number", "JD");
        dataObj.put("m4p4_consignee_number", "ID-000005");
        // 创建receipt_entry数组
        JSONArray receiptEntryArray = new JSONArray();

        // 创建单个receipt_entry对象
        JSONObject receiptEntryObj = new JSONObject();
        receiptEntryObj.put("m4p4_contract_no", "CSFGHT25080902");
        receiptEntryObj.put("m4p4_contract_num", "002");
        receiptEntryObj.put("m4p4_item_name", "电视");
        receiptEntryObj.put("m4p4_model_params", "1/台");
        receiptEntryObj.put("m4p4_brand", "华视");
        receiptEntryObj.put("m4p4_requisition_no", "DDBH-20251213-005");
        receiptEntryObj.put("m4p4_order_quantity", 225.00);
        receiptEntryObj.put("m4p4_receipt_quantity", 225.00);
        receiptEntryObj.put("m4p4_device_serial_no", "CPD5");
        receiptEntryObj.put("m4p4_asset_class_number", "F03");
        receiptEntryObj.put("m4p4_unit_number", "pcs");
        receiptEntryObj.put("m4p4_requisition_org_number", "1000");
        receiptEntryObj.put("m4p4_cost_center_number", "0001040107");
        receiptEntryObj.put("m4p4_storage_location_number", "001");
        receiptEntryObj.put("seq", 1);
        receiptEntryObj.put("m4p4_checkno", "YSD-20251213-005");

        receiptEntryArray.add(receiptEntryObj);
        dataObj.put("m4p4_receipt_entry", receiptEntryArray);
        dataArray.add(dataObj);
        mainObj.put("data", dataArray);
    }
}
