package com.jwipc.contract.logic.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Pair;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Sets;
import com.jwipc.constant.DelFlag;
import com.jwipc.contract.convert.ContractReturnOrderConvert;
import com.jwipc.contract.convert.ContractReturnOrderDetailsConvert;
import com.jwipc.contract.dto.*;
import com.jwipc.contract.entity.ContractDelivery;
import com.jwipc.contract.entity.ContractDeliveryDetail;
import com.jwipc.contract.entity.ContractReturnOrder;
import com.jwipc.contract.entity.ContractReturnOrderDetail;
import com.jwipc.contract.logic.ContractDeliveryLogic;
import com.jwipc.contract.logic.ContractReturnOrdersLogic;
import com.jwipc.contract.model.query.ContractReturnOrderQuery;
import com.jwipc.contract.service.IContractReturnOrderDetailService;
import com.jwipc.contract.service.IContractReturnOrderService;
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.service.IBusinessAttachmentService;
import com.jwipc.sys.util.FinancialShareUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
@RequiredArgsConstructor
@Slf4j
public class ContractReturnOrdersLogicImpl implements ContractReturnOrdersLogic {

    private final IContractReturnOrderService contractReturnOrderService;
    private final IContractReturnOrderDetailService contractReturnOrderDetailService;
    private final ContractReturnOrderConvert contractReturnOrderConvert;
    private final ContractReturnOrderDetailsConvert contractReturnOrderDetailsConvert;
    private final SequenceClient sequenceClient;
    private final FinancialShareUtil financialShareUtil;
    private final FinancialShareClient financialShareClient;
    private final ContractDeliveryLogic contractDeliveryLogic;
    private final IBusinessAttachmentService businessAttachmentService;
    private final static String  CONTRACT_DELIVERY = " ContractReturnOrderLock_";
    private final StringRedisTemplate redisTemplate;
    @Override
    public ContractReturnOrdersLookupDTO getReturnOrderById(Long id) {
        ContractReturnOrder contractReturnOrder = contractReturnOrderService.getById(id);
        ContractReturnOrdersLookupDTO dto = contractReturnOrderConvert.entity2LookupDTO(contractReturnOrder);
        return dto;
    }

    @Override
    public Pair<String, Set<String>> saveOrUpdate(ContractReturnOrderSaveDTO saveDTO) {
        final String lockKey = CONTRACT_DELIVERY + LoginUtil.getUserId();
        if (!redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS)) {
            log.info("系统正在处理，请稍后");
            throw new DaoException("系统正在处理，请稍后提交!");
        }
        ContractReturnOrder returnOrder = contractReturnOrderConvert.dto2Entity(saveDTO);
        List<ContractReturnOrderDetailSaveDTO> saveDTOItem = saveDTO.getItem();
        if (CollectionUtils.isEmpty(saveDTOItem)) {
            throw new DaoException("没有退货单明细行");
        }

        //退货数量校验码，已收货、已退货数量、可退货需要数量实时计算
        List<String> dataKeys = saveDTOItem.stream()
                .map(d -> d.getContractNo() + "_" + d.getContractSeq())
                .distinct()
                .collect(Collectors.toList());
        ContractOrderQuantityDTO contactOrderNumData = contractDeliveryLogic.findContactOrderNumData(dataKeys);
        Map<String, BigDecimal> returntMap = contactOrderNumData.getReturntMap();//订单行退货数量
        Map<String, BigDecimal> receiveNumMap = contactOrderNumData.getReceiveNumMap();//订单行已收货数量
        Map<String, Integer> checkMap = new HashMap<>();
        //送货单订单+行号重复校验
        for (ContractReturnOrderDetailSaveDTO orderDetail : saveDTOItem) {
           String keys = orderDetail.getContractNo()+"_"+orderDetail.getContractSeq();
            BigDecimal returnNum = returntMap.get(keys) == null ?  BigDecimal.ZERO : returntMap.get(keys);
            BigDecimal receiveNum = receiveNumMap.get(keys) == null ? BigDecimal.ZERO : receiveNumMap.get(keys);
            if(orderDetail.getReturnQuantity().compareTo(receiveNum.subtract(returnNum)) > 0){
                throw new DaoException("退货单合同编号和行号"+keys+",填写的退货数量大于实际可退货数量");
            }
            //校验退货数量 + 已退数量 <= 收货数量
            if((orderDetail.getReturnQuantity().add(returnNum)).compareTo(receiveNum) > 0){
                throw new DaoException("退货单合同编号和行号"+keys+",填写的本次退货数量+已退货数量不能大于收货数量");
            }
            String deliveryNo = orderDetail.getDeliveryNo();
            String receiptLineNo = orderDetail.getReceiptLineNo();
            String key = deliveryNo+":"+receiptLineNo;
            if( checkMap.get(key) == null){
                checkMap.put(key,1);
            }else{
                checkMap.put(key,checkMap.get(key) + 1);
            }
        }
        int rowNo = 0;
        for (ContractReturnOrderDetailSaveDTO orderDetail : saveDTOItem) {
            String deliveryNo = orderDetail.getDeliveryNo();
            String receiptLineNo = orderDetail.getReceiptLineNo();
            String key = deliveryNo+":"+receiptLineNo;
            //            if(checkMap.get(key) > 1){
//                final String format = StrUtil.format("创建合同退货单失败:{}-{},交货单编号和交货单行号重复", deliveryNo,
//                        receiptLineNo);
//                throw new DaoException(format);
//            }
            rowNo++;
            orderDetail.setReturnOrderLine(String.valueOf(rowNo));
        }
        List<ContractReturnOrderDetail> returnOrderDetails =  contractReturnOrderDetailsConvert.dtos2Entities(saveDTOItem);
        if(returnOrder.getId() == null){
         //   String returnOrderNo = sequenceClient.getCodeSequenceNo("contract_return_order", 5);
            String returnOrderNo = sequenceClient. getBarCodeSequenceNo("contract_return_order", 8,false);

            returnOrder.setReturnOrderNo(returnOrderNo);
            returnOrder.setDeleteFlag(0);
            returnOrder.setDeliveryStatus(4);
            returnOrder.setCreateId(LoginUtil.getUserId());
            returnOrder.setCreateTime(LocalDateTime.now());
            if(contractReturnOrderService.save(returnOrder)){
                    returnOrderDetails.stream()
                            .forEach(detail -> {
                                detail.setReturnOrderId(returnOrder.getId());
                                detail.setReturnOrderNo(returnOrderNo);
                                detail.setDeleteFlag(0);
                                detail.setCreateId(LoginUtil.getUserId());
                                detail.setCreateTime(LocalDateTime.now());
                            });
                    contractReturnOrderDetailService.saveBatch(returnOrderDetails);
            }
        }
        Set<Long> ids = Sets.newHashSet();
        Set<String> msg = Sets.newHashSet();
        msg.add("创建成功");
        return Pair.of(ids.stream().map(String::valueOf).collect(Collectors.joining(",")), msg);
    }

    @Override
    public PageView getContractReturnOrderList(ContractReturnOrderQuery query) {
        Page<ContractReturnOrder> page = PageUtil.toPage(query);
        List<ContractReturnOrder> list = contractReturnOrderService.findList(page, query);
        List<ContractReturnOrderDTO> dtos = contractReturnOrderConvert.entities2Dtos(list);
        final Set<Long> ids = dtos.stream().map(ContractReturnOrderDTO::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_order_return"));
            final Map<Long, List<Long>> businessAttachmentMap = businessAttachmentList.stream().collect(
                    Collectors.groupingBy(BusinessAttachment::getBusinessId,
                            Collectors.mapping(BusinessAttachment::getFileId, Collectors.toList())));
            for (ContractReturnOrderDTO dto : dtos) {
                if (Objects.nonNull(businessAttachmentMap.get(dto.getId()))) {
                    dto.setAttachmentFiles("1");
                }
            }
        }
        return PageUtil.getPV(dtos, page.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ContractReturnOrderSaveDTO dto) {
        ContractReturnOrder contractReturnOrder = contractReturnOrderConvert.dto2Entity(dto);
        contractReturnOrder.setUpdateId(LoginUtil.getUserId());
        contractReturnOrder.setUpdateTime(LocalDateTime.now());
        contractReturnOrderService.updateById(contractReturnOrder);
        List<ContractReturnOrderDetailSaveDTO> item = dto.getItem();
        //校验退货数量是否允许修改
        List<String> dataKeys = item.stream()
                .map(d -> d.getContractNo() + "_" + d.getContractSeq())
                .distinct()
                .collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(dataKeys)){
            ContractOrderQuantityDTO contactOrderNumData = contractDeliveryLogic.findContactOrderNumData(dataKeys);
            Map<String, BigDecimal> returntMap = contactOrderNumData.getReturntMap();//订单行退货数量
            Map<String, BigDecimal> receiveNumMap = contactOrderNumData.getReceiveNumMap();//订单行已收货数量
            List<ContractReturnOrderDetail> updateLists = new ArrayList();
            if (CollectionUtils.isNotEmpty(item)) {
                for (ContractReturnOrderDetailSaveDTO detailSaveDTO : item) {
                    //进行退货数量校验
                    String key = detailSaveDTO.getContractNo()+"_"+detailSaveDTO.getContractSeq();
                    BigDecimal returntNum = returntMap.get(key) == null ? BigDecimal.ZERO : returntMap.get(key);
                    BigDecimal receiveNum = receiveNumMap.get(key) == null ? BigDecimal.ZERO : receiveNumMap.get(key);
                    if(detailSaveDTO.getReturnQuantity().compareTo(receiveNum.subtract(returntNum)) > 0){
                        throw new DaoException("退货单合同编号和行号"+key+",填写的退货数量大于实际可退货数量");
                    }
                    detailSaveDTO.setUpdateTime(LocalDateTime.now());
                    detailSaveDTO.setUpdateId(LoginUtil.getUserId());
                    ContractReturnOrderDetail detail = contractReturnOrderDetailsConvert.dto2Entity(detailSaveDTO);
                    updateLists.add(detail);
                }
                contractReturnOrderDetailService.updateBatchById(updateLists);
            }
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmretuenOrder(Long id) {
        ContractReturnOrder returnOrder = new ContractReturnOrder();
        returnOrder.setId(id);
        returnOrder.setDeliveryStatus(5);
        returnOrder.setUpdateTime(LocalDateTime.now());
        returnOrder.setUpdateId(LoginUtil.getUserId());
        contractReturnOrderService.updateById(returnOrder);
        //查询退货单主表数据及退货单明细表，调用共享接口
        ContractReturnOrder order = contractReturnOrderService.getById(id);
        if(order != null){
            List<ContractReturnOrderDetail> list = contractReturnOrderDetailService.list(new LambdaQueryWrapper<ContractReturnOrderDetail>().eq(ContractReturnOrderDetail::getReturnOrderId, id));
            if(!CollectionUtils.isEmpty(list)){
                JSONObject jsonObject = postGxReceiptBill(order, list);
                LambdaUpdateWrapper<ContractReturnOrder> update = new LambdaUpdateWrapper<ContractReturnOrder>()
                        .set(ContractReturnOrder::getSyncGxNo,jsonObject.getString("number"))
                        .set(ContractReturnOrder::getSyncGxId,jsonObject.getString("id"))
                        .set(ContractReturnOrder::getSyncState,0)
                        .eq(ContractReturnOrder::getId,id);
                contractReturnOrderService.update(update);
            }
        }
    }

    @Override
    public void retuenOrderRemove(Long id) {
        ContractReturnOrder returnOrder = new ContractReturnOrder();
        returnOrder.setId(id);
        returnOrder.setDeleteFlag(DelFlag.DELETE.getStatus());
        returnOrder.setUpdateTime(LocalDateTime.now());
        returnOrder.setUpdateId(LoginUtil.getUserId());
        contractReturnOrderService.updateById(returnOrder);
        contractReturnOrderDetailService.update(
                new LambdaUpdateWrapper<ContractReturnOrderDetail>().set(ContractReturnOrderDetail::getDeleteFlag,
                                DelFlag.DELETE.getStatus())
                        .set(ContractReturnOrderDetail::getUpdateTime,LocalDateTime.now())
                        .set(ContractReturnOrderDetail::getUpdateId,LoginUtil.getUserId())
                        .eq(ContractReturnOrderDetail::getReturnOrderId, id));
    }

    private JSONObject postGxReceiptBill(ContractReturnOrder returnOrder, List<ContractReturnOrderDetail> list){
        String shareAccessToken = financialShareUtil.getShareAccessToken();
        JSONObject mainObj = new JSONObject(); // 创建最外层JSON对象
        JSONArray dataArray = new JSONArray();// 创建data数组
        // 创建单个data对象
        JSONObject dataObj = new JSONObject();
        dataObj.put("billno", returnOrder.getReturnOrderNo());
        dataObj.put("m4p4_billtype", "02");//退货类型
        dataObj.put("m4p4_receipt_date",returnOrder.getReturnOrderDate());//退货日期  --没有取到值
        dataObj.put("m4p4_receipt_status", "01");//单据状态收货状态
        dataObj.put("org_number",returnOrder.getPurchaserCode());//购货方.编码 --没有取到值
        dataObj.put("m4p4_supplier_number", returnOrder.getSupplierCode());//供应商.编码 --没有取到值
        dataObj.put("m4p4_consignee_number", returnOrder.getReceiver());//receiver退货人  --没有取到值
        // 创建receipt_entry数组
        JSONArray receiptEntryArray = new JSONArray();
        for (ContractReturnOrderDetail detail : list) {
            // 创建单个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.getReturnQuantity());//收货明细.退货数量 -- 没有取到
            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.getReturnOrderLine());//收货明细.分录行号
            receiptEntryArray.add(receiptEntryObj);
            receiptEntryObj.put("m4p4_unit_price",detail.getNoTaxPrice() );//未税单价
            receiptEntryObj.put("m4p4_unit_price_tax",detail.getPrice());//含税单价
            receiptEntryObj.put("m4p4_custodian_number",detail.getUserCode());//含税单价
        }
        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;
    }
}
