package com.sw.mes.store.api.interfaces.supplier;


import com.alibaba.fastjson.JSON;
import com.sw.mes.core.api.materialclean.MaterialCleanFeignClients;
import com.sw.mes.core.api.system.YbFeignClients;
import com.sw.mes.core.context.BaseContextHandler;
import com.sw.mes.core.dto.DictionaryItemDto;
import com.sw.mes.core.dto.materialCleanDto.MaterialStoreSignBoxDto;
import com.sw.mes.core.dto.store.*;
import com.sw.mes.core.enums.InputBillTypeEnum;
import com.sw.mes.core.exception.BusinessException;
import com.sw.mes.core.response.Result;
import com.sw.mes.core.response.ResultCode;
import com.sw.mes.core.response.ResultGenerator;
import com.sw.mes.core.utils.BeanUtil;
import com.sw.mes.store.dto.*;
import com.sw.mes.store.dto.LockInventoryDto;
import com.sw.mes.store.dto.StoreDto;
import com.sw.mes.store.dto.WarehouseAllotBillDetailDto;
import com.sw.mes.store.dto.WarehouseAllotBillDto;
import com.sw.mes.store.dto.WarehouseInputRecordBillDetailDto;
import com.sw.mes.store.dto.WarehouseInputReturnDto;
import com.sw.mes.store.dto.WarehouseInventoryDto;
import com.sw.mes.store.entity.*;
import com.sw.mes.store.enums.*;
import com.sw.mes.store.mapper.WarehouseModelMapper;
import com.sw.mes.store.service.*;
import com.sw.mes.store.utils.CodeGenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 外部调用线边仓的接口
 * @Author wupeng
 * @Date 2023/12/22 16:45
 **/
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class WarehouseSupplierServiceImpl implements WarehouseSupplierService {

    private static final Logger logger = LoggerFactory.getLogger(WarehouseSupplierServiceImpl.class);
    @Autowired
    private ModelMapper modelMapper;

    @Autowired
    private WarehouseInputBillService warehouseInputBillService;

    @Autowired
    private WarehouseInputRecordBillDetailService warehouseInputRecordBillDetailService;
    @Autowired
    private WarehouseInputBillDetailService warehouseInputBillDetailService;
    @Autowired
    private WarehouseOutputBillService warehouseOutputBillService;

    @Autowired
    private WarehouseInventoryService inventoryService;

    @Autowired
    private WarehouseAllotBillService warehouseAllotBillService;

    @Autowired
    private WarehouseAllotBillDetailService warehouseAllotBillDetailService;

    @Autowired
    private WarehouseModelMapper warehouseModelMapper;

    @Autowired
    private MaterialCleanFeignClients materialCleanFeignClients;

    @Autowired
    private WarehouseInventoryService warehouseInventoryService;

    @Autowired
    private WarehouseAllotRecordBillService warehouseAllotRecordBillService;

    @Autowired
    private WarehouseAllotRecordBillDetailService warehouseAllotRecordBillDetailService;

    @Autowired
    private WarehouseModelService warehouseModelService;

    @Autowired
    private WarehouseMaterialService warehouseMaterialService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private YbFeignClients ybFeignClients;

    @Autowired
    private WarehouseOutputRecordBillDetailService warehouseOutputRecordBillDetailService;

    @Override
    public String input(WarehouseInputBillBo inputBillBo) {
        if (inputBillBo == null || CollectionUtils.isEmpty(inputBillBo.getInputBillDetails())) {
            throw new BusinessException("入库数据为空");
        }
        WarehouseInputBillDto warehouseInputBill = new WarehouseInputBillDto();
        List<WarehouseInputBillDetailDto> warehouseInputBillDetailDtos = new ArrayList<>();
        BeanUtils.copyProperties(inputBillBo, warehouseInputBill, "inputBillDetails");
        inputBillBo.getInputBillDetails().stream().forEach(entity -> {
            WarehouseInputBillDetailDto warehouseInputBillDetailDto = new WarehouseInputBillDetailDto();
            BeanUtils.copyProperties(entity, warehouseInputBillDetailDto, "id");
            warehouseInputBillDetailDtos.add(warehouseInputBillDetailDto);
        });
        warehouseInputBill.setInputBillDetails(warehouseInputBillDetailDtos);
        warehouseInputBillService.saveInputBill(warehouseInputBill);
        return warehouseInputBill.getBillNo();
    }

    @Override
    public WarehouseInputReturnDto inputData(WarehouseInputBillBo inputBillBo) {
        if (inputBillBo == null || CollectionUtils.isEmpty(inputBillBo.getInputBillDetails())) {
            throw new BusinessException("入库数据为空");
        }
        WarehouseInputBillDto warehouseInputBill = new WarehouseInputBillDto();
        List<WarehouseInputBillDetailDto> warehouseInputBillDetailDtos = new ArrayList<>();
        BeanUtils.copyProperties(inputBillBo, warehouseInputBill, "inputBillDetails");
        inputBillBo.getInputBillDetails().stream().forEach(entity -> {
            WarehouseInputBillDetailDto warehouseInputBillDetailDto = new WarehouseInputBillDetailDto();
            BeanUtils.copyProperties(entity, warehouseInputBillDetailDto, "id");
            warehouseInputBillDetailDtos.add(warehouseInputBillDetailDto);
        });
        warehouseInputBill.setInputBillDetails(warehouseInputBillDetailDtos);
        warehouseInputBillService.saveInputBill(warehouseInputBill);
        WarehouseInputReturnDto warehouseInputReturnDto = new WarehouseInputReturnDto();
        warehouseInputReturnDto.setBillNo(warehouseInputBill.getBillNo());
        warehouseInputReturnDto.setWarehouseCode(warehouseInputBill.getInputBillDetails().get(0).getWarehouseCode());
        warehouseInputReturnDto.setCustomer(warehouseInputBill.getInputBillDetails().get(0).getCustomer());
        return warehouseInputReturnDto;
    }

    @Override
    public String output(WarehouseOutputBillBo outputBillBo) {
        if (outputBillBo == null || CollectionUtils.isEmpty(outputBillBo.getOutputBillDetails())) {
            throw new BusinessException("出库数据为空");
        }
//        WarehouseOutputBill warehouseOutputBill = modelMapper.map(outputBillBo, WarehouseOutputBill.class);
        WarehouseOutputBill warehouseOutputBill = new WarehouseOutputBill();
        BeanUtils.copyProperties(outputBillBo, warehouseOutputBill, "id");
        List<WarehouseOutputBillDetail> targetDetailList = new ArrayList<>();
        copyDetails(targetDetailList, outputBillBo.getOutputBillDetails());
        warehouseOutputBill.setOutputBillDetails(targetDetailList);
        //BeanUtil.copyProperties(warehouseOutputBill, outputBillBo);
        warehouseOutputBillService.saveOutputBill(warehouseOutputBill);
        return warehouseOutputBill.getBillNo();
    }

    /**
     * 锁定库存
     *
     * @param lockInventoryDto
     */
    @Override
    public void lockInventory(List<LockInventoryDto> lockInventoryDto) {
        if (CollectionUtils.isEmpty(lockInventoryDto)) {
            throw new BusinessException("锁定数据为空");
        }
        //当开启了唯一码，用于判断是否存在相同的唯一码，只要唯一码不同，其他字段可以相同
        Set<String> uniqueCodeSet = new HashSet<>();
        //锁定库存
        for (LockInventoryDto lockInventory : lockInventoryDto) {
            String uniqueCode = lockInventory.getUniqueCode();
            if (StringUtils.isNotBlank(uniqueCode)) {
                //校验当前即将出库的明细中唯一码是否重复
                if (!uniqueCodeSet.add(uniqueCode)) {
                    throw new BusinessException("唯一码【" + uniqueCode + "】重复，请检查数据！");
                }
            }
            BigDecimal requireCount = lockInventory.getQuantity();
            String batchNo = lockInventory.getBatchNo();
            String materialModelCode = lockInventory.getMaterialModelCode();
            Long warehouseId = lockInventory.getWarehouseId();
            if (StringUtils.isNotBlank(uniqueCode)) {
                //如果库存存在则需要把锁定对应库存的数量
                WarehouseInventory warehouseInventory = inventoryService.getByUniqueCode(uniqueCode);
                if (ObjectUtils.isNotEmpty(warehouseInventory)) {
                    BigDecimal quantity = warehouseInventory.getQuantity();
                    BigDecimal lockQuantity = warehouseInventory.getLockQuantity() == null ? new BigDecimal("0") : warehouseInventory.getLockQuantity();
                    BigDecimal remain = quantity.subtract(lockQuantity);
                    if (requireCount.compareTo(remain) == 1) {
                        //出库数量大于库存数量
                        throw new BusinessException("批次号【" + batchNo + "】，物料编码【" + materialModelCode + "】对应的库存不足，请检查数据！");
                    }
                    BigDecimal number = requireCount.add(lockQuantity);
                    warehouseInventory.setLockQuantity(number);
                    inventoryService.updateById(warehouseInventory);
                } else {
                    throw new BusinessException("唯一码【" + uniqueCode + "】对应的物料库存不足，请重新选择！");
                }
            } else {
                //根据 唯一码为空、批次号、物料、库位  查询物料库存数据
                List<WarehouseInventory> warehouseInventory = inventoryService.getByMaterialAndBatchNoAndWarehouseId(batchNo,
                        materialModelCode, warehouseId);
                if (CollectionUtils.isEmpty(warehouseInventory)) {
                    throw new BusinessException("批次号【" + batchNo + "】，物料编码【" + materialModelCode + "】对应的库存数据不存在，请检查数据！");
                }
                if (warehouseInventory.size() > 1) {
                    throw new BusinessException("批次号【" + batchNo + "】，物料编码【" + materialModelCode + "】对应的库存数据存在多条，请检查数据！");
                }
                warehouseInventory = warehouseInventory.stream().filter(e -> StringUtils.isBlank(e.getUniqueCode())).collect(Collectors.toList());
                WarehouseInventory inventory = warehouseInventory.get(0);
                BigDecimal quantity = inventory.getQuantity();
                BigDecimal lockQuantity = inventory.getLockQuantity() == null ? new BigDecimal("0") : inventory.getLockQuantity();
                BigDecimal remain = quantity.subtract(lockQuantity);
                if (requireCount.compareTo(remain) == 1) {
                    //出库数量大于库存数量
                    throw new BusinessException("批次号【" + batchNo + "】，物料编码【" + materialModelCode + "】对应的库存不足，请检查数据！");
                }
                BigDecimal number = requireCount.add(lockQuantity);
                inventory.setLockQuantity(number);
                inventoryService.updateById(inventory);
            }
        }
    }

    /**
     * 解锁库存
     *
     * @param lockInventoryDto
     */
    @Override
    public void unLockInventory(List<LockInventoryDto> lockInventoryDto) {
        if (CollectionUtils.isEmpty(lockInventoryDto)) {
            throw new BusinessException("出库数据为空");
        }
        //当开启了唯一码，用于判断是否存在相同的唯一码，只要唯一码不同，其他字段可以相同
        Set<String> uniqueCodeSet = new HashSet<>();
        //锁定库存
        for (LockInventoryDto lockInventory : lockInventoryDto) {
            String uniqueCode = lockInventory.getUniqueCode();
            if (StringUtils.isNotBlank(uniqueCode)) {
                //校验当前即将出库的明细中唯一码是否重复
                if (!uniqueCodeSet.add(uniqueCode)) {
                    throw new BusinessException("唯一码【" + uniqueCode + "】重复，请检查数据！");
                }
            }
            String materialModelCode = lockInventory.getMaterialModelCode();
            if (StringUtils.isBlank(materialModelCode)) {
                throw new BusinessException("出库的物料编码为空，请检查数据");
            }
            Long warehouseId = lockInventory.getWarehouseId();
            if (warehouseId == null || warehouseId == 0) {
                throw new BusinessException("出库明细的库位信息为空，请检查数据");
            }
            String batchNo = lockInventory.getBatchNo();
            BigDecimal requireCount = lockInventory.getQuantity(); //需求数量，是创建出库单时，需要的数量
            if (StringUtils.isNotBlank(uniqueCode)) {
                //如果库存存在则需要把锁定对应库存的数量
                WarehouseInventory warehouseInventory = inventoryService.getByUniqueCode(uniqueCode);
                if (ObjectUtils.isNotEmpty(warehouseInventory)) {
                    BigDecimal lockQuantity = warehouseInventory.getLockQuantity() == null ? new BigDecimal("0") : warehouseInventory.getLockQuantity();
                    if (lockQuantity.compareTo(new BigDecimal("0")) <= 0 || requireCount.compareTo(lockQuantity) > 0) {
                        //锁定数量小于等于0 或者 解锁数量大于锁定数量
                        throw new BusinessException("锁定数量小于解锁数量，请检查数据！");
                    }
                    BigDecimal number = lockQuantity.subtract(requireCount);
                    warehouseInventory.setLockQuantity(number);
                    inventoryService.updateById(warehouseInventory);
                } else {
                    throw new BusinessException("唯一码【" + uniqueCode + "】对应的物料库存不存在，请重新选择！");
                }
            } else {
                //根据 唯一码为空、批次号、物料、库位  查询物料库存数据
                List<WarehouseInventory> warehouseInventory = inventoryService.getByMaterialAndBatchNoAndWarehouseId(batchNo,
                        materialModelCode, warehouseId);
                if (CollectionUtils.isEmpty(warehouseInventory)) {
                    throw new BusinessException("批次号【" + batchNo + "】，物料编码【" + materialModelCode + "】对应的库存数据存在多条，请检查数据！");
                }
                if (warehouseInventory.size() > 1) {
                    throw new BusinessException("批次号【" + batchNo + "】，物料编码【" + materialModelCode + "】对应的库存数据存在多条，请检查数据！");
                }
                warehouseInventory = warehouseInventory.stream().filter(e -> StringUtils.isBlank(e.getUniqueCode())).collect(Collectors.toList());
                WarehouseInventory inventory = warehouseInventory.get(0);
                BigDecimal lockQuantity = inventory.getLockQuantity() == null ? new BigDecimal("0") : inventory.getLockQuantity();
                if (lockQuantity.compareTo(new BigDecimal("0")) <= 0 || requireCount.compareTo(lockQuantity) > 0) {
                    //锁定数量小于等于0 或者 解锁数量大于锁定数量
                    throw new BusinessException("锁定数量小于解锁数量，请检查数据！");
                }
                BigDecimal number = lockQuantity.subtract(requireCount);
                inventory.setLockQuantity(number);
                inventoryService.updateById(inventory);
            }
        }
    }

    @Override
    public WarehouseInputReturnDto outputData(WarehouseOutputBillBo outputBillBo) {
        if (outputBillBo == null || CollectionUtils.isEmpty(outputBillBo.getOutputBillDetails())) {
            throw new BusinessException("出库数据为空");
        }
        //        WarehouseOutputBill warehouseOutputBill = modelMapper.map(outputBillBo, WarehouseOutputBill.class);
        WarehouseOutputBill warehouseOutputBill = new WarehouseOutputBill();
        BeanUtils.copyProperties(outputBillBo, warehouseOutputBill, "id");
        List<WarehouseOutputBillDetail> targetDetailList = new ArrayList<>();
        copyDetails(targetDetailList, outputBillBo.getOutputBillDetails());
        warehouseOutputBill.setOutputBillDetails(targetDetailList);
        //BeanUtil.copyProperties(warehouseOutputBill, outputBillBo);
        warehouseOutputBillService.saveOutputBill(warehouseOutputBill);
        WarehouseInputReturnDto warehouseInputReturnDto = new WarehouseInputReturnDto();
        warehouseInputReturnDto.setBillNo(warehouseOutputBill.getBillNo());
        warehouseInputReturnDto.setWarehouseCode(warehouseOutputBill.getOutputBillDetails().get(0).getWarehouseCode());
        warehouseInputReturnDto.setCustomer(warehouseOutputBill.getOutputBillDetails().get(0).getCustomer());
        return warehouseInputReturnDto;
    }

    private void copyDetails(List<WarehouseOutputBillDetail> targetList, List<WarehouseOutputBillDetailBo> sourceList) {
        for (WarehouseOutputBillDetailBo source : sourceList) {
            //WarehouseOutputBillDetail target = modelMapper.map(source, WarehouseOutputBillDetail.class);
            WarehouseOutputBillDetail target = new WarehouseOutputBillDetail();
            BeanUtils.copyProperties(source, target, "id");
            targetList.add(target);
        }
    }

    @Override
    public void cancelInput(String billNo) {
        warehouseInputBillService.cancelApply(billNo);
    }

    @Override
    public void cancelOutput(String billNo) {
        warehouseOutputBillService.cancelApply(billNo);
    }

    @Override
    public List<WarehouseInventory> findByBatchNo(String batchNo) {
        List<WarehouseInventory> warehouseInventories = inventoryService.getByBatchNo(batchNo);
        return warehouseInventories;
    }

    /**
     * 对外创建调拨单接口
     *
     * @param warehouseAllotBillDto
     * @return
     */
    @Override
    public Boolean createAllotBill(WarehouseAllotBillDto warehouseAllotBillDto) {
        List<WarehouseAllotBillDetailDto> details = warehouseAllotBillDto.getAllotBillDetailDtos();
        if (CollectionUtils.isEmpty(details)) {
            throw new BusinessException("调拨明细为空，请检查数据！");
        }
        //调拨单号
        String billNo = StringUtils.isNotBlank(warehouseAllotBillDto.getBillNo()) ? warehouseAllotBillDto.getBillNo() : CodeGenUtil.genAllotBillNo();
        WarehouseAllotBill oldAllotBill = warehouseAllotBillService.getByBillNo(billNo);
        if (ObjectUtils.isNotEmpty(oldAllotBill)) {
            throw new BusinessException("调拨单号已存在，请检查数据！");
        }
        WarehouseModel warehouseModel = warehouseModelService.getCode(warehouseAllotBillDto.getAllotBillDetailDtos().get(0).getAllotWarehouseCode());
        if (ObjectUtils.isEmpty(warehouseModel)) {
            throw new BusinessException("调拨库位" + warehouseAllotBillDto.getAllotBillDetailDtos().get(0).getAllotWarehouseCode() + "不存在，请维护！");
        }
        WarehouseAllotBill allotBill = new WarehouseAllotBill();
        BeanUtils.copyProperties(warehouseAllotBillDto, allotBill);
        allotBill.setBillNo(billNo);
        if (StringUtils.isEmpty(allotBill.getAllotType())) {
            allotBill.setAllotType(AllotBillTypeEnum.手动新建.getValue());
        }
        allotBill.setCreateTime(new Date());
        if (ObjectUtils.isEmpty(allotBill.getUpdateUserId())) {
            allotBill.setUpdateUserId(allotBill.getCreateUserId());
        }
        if (ObjectUtils.isEmpty(allotBill.getUpdateUserName())) {
            allotBill.setUpdateUserName(allotBill.getCreateUserName());
        }
        if (ObjectUtils.isEmpty(allotBill.getCreateUserId())) {
            allotBill.setCreateUserId(BaseContextHandler.getUserID());
        }
        if (ObjectUtils.isEmpty(allotBill.getCreateUserName())) {
            allotBill.setCreateUserName(BaseContextHandler.getUsername());
        }
        allotBill.setStatus(AllotBillStatusEnum.待审核.getValue());
        allotBill.setAllotWarehouseId(warehouseModel.getId());
        allotBill.setAllotWarehouseName(warehouseModel.getName());
        //保存入库单
        warehouseAllotBillService.saveOrUpdate(allotBill);
        //保存调拨单记录
//        WarehouseAllotRecordBill recordBill = new WarehouseAllotRecordBill();
//        List<WarehouseAllotRecordBillDetail> allotRecordBillDetails = new ArrayList<>();
//        BeanUtils.copyProperties(allotBill, recordBill, "id");
//        recordBill.setAllotBillNo(allotBill.getBillNo());
//        recordBill.setAllotBillId(allotBill.getId());
//        recordBill.setRecordBillNo(allotBill.getBillNo());
//        warehouseAllotRecordBillService.save(recordBill);
        List<WarehouseAllotBillDetail> detaiList = new ArrayList<>(details.size());
        //当开启了唯一码，用于判断是否存在相同的唯一码
        Set<String> uniqueCodeSet = new HashSet<>();
        for (WarehouseAllotBillDetailDto allotBillDetail : details) {
            String uniqueCode = allotBillDetail.getUniqueCode();
            if (StringUtils.isNotBlank(uniqueCode)) {
                //校验调拨明细中唯一码是否重复
                boolean add = uniqueCodeSet.add(uniqueCode);
                //查询是否已存在重复唯一码
                if (!add) {
                    throw new BusinessException("唯一码【" + uniqueCode + "】重复，请检查数据重新输入！");
                } else {
                    BigDecimal count = allotBillDetail.getCount();
                    //唯一码物料库存只能是 1
                    if (count.compareTo(new BigDecimal(1)) != 0) {
                        throw new BusinessException("唯一码【" + uniqueCode + "】物料调拨数量只能为1，请检查数据重新输入！");
                    }
                }
            }
            if (ObjectUtils.isEmpty(warehouseAllotBillDto.getAllotBillDetailDtos().get(0).getWarehouseId())
                    && ObjectUtils.isEmpty(warehouseAllotBillDto.getAllotBillDetailDtos().get(0).getWarehouseCode())) {
                throw new BusinessException("申请入库单库位编码或者库位id必填,请检查数据!");
            }
            WarehouseInventory warehouseInventory = new WarehouseInventory();
            if (null != warehouseAllotBillDto.getAllotBillDetailDtos().get(0).getWarehouseId()) {
                List<WarehouseInventory> warehouseInventories = inventoryService.getByMaterialAndBatchNoAndWarehouseId(warehouseAllotBillDto.getAllotBillDetailDtos().get(0).getBatchNo(), allotBillDetail.getMaterialModelCode(),
                        warehouseAllotBillDto.getAllotBillDetailDtos().get(0).getWarehouseId());
                if (warehouseInventories.size() > 0) {
                    warehouseInventory = warehouseInventories.get(0);
                }
            }
            if (StringUtils.isNotBlank(warehouseAllotBillDto.getAllotBillDetailDtos().get(0).getWarehouseCode()) && null == warehouseInventory) {
                List<WarehouseInventory> warehouseInventories = inventoryService.getByMaterialAndBatchNoAndWarehouseCode(warehouseAllotBillDto.getAllotBillDetailDtos().get(0).getBatchNo(),
                        allotBillDetail.getMaterialModelCode(), warehouseAllotBillDto.getAllotBillDetailDtos().get(0).getWarehouseCode());
                if (warehouseInventories.size() > 0) {
                    warehouseInventory = warehouseInventories.get(0);
                }
            }
            WarehouseAllotBillDetail detail = new WarehouseAllotBillDetail();
            BeanUtils.copyProperties(allotBillDetail, detail);
            detail.setRemark(allotBill.getRemark());
            detail.setStatus(AllotBillStatusEnum.待审核.getValue());
            detail.setAllotBillId(allotBill.getId());
            detail.setAllotBillNo(allotBill.getBillNo());
            detail.setCreateTime(allotBill.getCreateTime());
            detail.setCreateUserId(allotBill.getCreateUserId());
            detail.setCreateUserName(allotBill.getCreateUserName());
            detail.setAllotWarehouseId(warehouseModel.getId());
            detail.setAllotWarehouseName(warehouseModel.getName());
            if (!ObjectUtils.isEmpty(warehouseInventory)) {
                detail.setInventoryId(warehouseInventory.getId());
            }
            detaiList.add(detail);
//            WarehouseAllotRecordBillDetail warehouseAllotRecordBillDetail = new WarehouseAllotRecordBillDetail();
//            BeanUtils.copyProperties(detail, warehouseAllotRecordBillDetail, "id");
//            warehouseAllotRecordBillDetail.setRecordBillId(recordBill.getId());
//            warehouseAllotRecordBillDetail.setRecordBillNo(recordBill.getRecordBillNo());
//            warehouseAllotRecordBillDetail.setAllotBillNo(detail.getAllotBillNo());
//            warehouseAllotRecordBillDetail.setAllotBillId(detail.getAllotBillId());
//            warehouseAllotRecordBillDetail.setCreateUserId(detail.getCreateUserId());
//            warehouseAllotRecordBillDetail.setCreateUserName(detail.getCreateUserName());
//            warehouseAllotRecordBillDetail.setCreateTime(detail.getCreateTime());
//            warehouseAllotRecordBillDetail.setAllotWarehouseId(Integer.valueOf(String.valueOf(warehouseModel.getId())));
//            warehouseAllotRecordBillDetail.setAllotWarehouseName(warehouseModel.getName());
//            warehouseAllotRecordBillDetail.setMaterialModelId(Integer.valueOf(String.valueOf(detail.getMaterialModelId())));
//            allotRecordBillDetails.add(warehouseAllotRecordBillDetail);
        }
        warehouseAllotBillDetailService.saveBatch(detaiList);
//        warehouseAllotRecordBillDetailService.saveBatch(allotRecordBillDetails);

        //如果是自动审核，直接入库
        if (allotBill.getAutoAudit()) {
            BeanUtil.copyBeanPropWithOutNullValue(warehouseAllotBillDto, allotBill);
            warehouseAllotBillService.autoReceiveAtomic(warehouseAllotBillDto);
        }
        return true;
    }

    /**
     * 自动出入库对外接口
     *
     * @param inputBillBo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result automaticInputOut(WarehouseInputBillBo inputBillBo) {
        if (inputBillBo == null || CollectionUtils.isEmpty(inputBillBo.getInputBillDetails())) {
            throw new BusinessException("入库数据为空");
        }
        //入库单号
        String inputBillNo = inputBillBo.getBillNo();
        inputBillNo = StringUtils.isNotBlank(inputBillNo) ? inputBillNo : CodeGenUtil.genInputBillNo();
        WarehouseInputBill byBillNo = warehouseInputBillService.getByBillNo(inputBillNo);
        if (byBillNo != null) {
            throw new BusinessException("入库单号【" + inputBillNo + "】已存在，请检查数据！");
        }
//        WarehouseInputBillDto warehouseInputBill = modelMapper.map(inputBillBo, WarehouseInputBillDto.class);
        WarehouseInputBillDto warehouseInputBill = new WarehouseInputBillDto();
        BeanUtils.copyProperties(inputBillBo, warehouseInputBill, "inputBillDetails");
        warehouseInputBill.setId(null);
        warehouseInputBill.setCreateTime(new Date());
        warehouseInputBill.setBillNo(inputBillNo);
        warehouseInputBill.setCreateUserId(BaseContextHandler.getUserID());
        warehouseInputBill.setCreateUserName(BaseContextHandler.getUsername());
        warehouseInputBill.setAutoAudit(true);
        List<WarehouseInputBillDetailDto> warehouseInputBillDetailDtos = JSON.parseArray(JSON.toJSONString(inputBillBo.getInputBillDetails()), WarehouseInputBillDetailDto.class);
        warehouseInputBill.setInputBillDetails(warehouseInputBillDetailDtos);
        warehouseInputBill.getInputBillDetails().stream().forEach(details -> {
            if (StringUtils.isNotBlank(details.getWarehouseCode())) {
                WarehouseModel warehouseModel = warehouseModelService.getCode(details.getWarehouseCode());
                if (ObjectUtils.isNotEmpty(warehouseModel)) {
                    details.setWarehouseId(warehouseModel.getId());
                    details.setWarehouseName(warehouseModel.getName());
                }
            }
            if (ObjectUtils.isNotEmpty(details.getWarehouseId()) && StringUtils.isEmpty(details.getWarehouseCode())) {
                WarehouseModel warehouseModel = warehouseModelService.getById(details.getWarehouseId());
                if (ObjectUtils.isNotEmpty(warehouseModel)) {
                    details.setWarehouseCode(warehouseModel.getCode());
                    details.setWarehouseName(warehouseModel.getName());
                }
            }
        });
        Result result = null;
        List<MaterialStoreSignBoxDto> storeSignBoxDtos = new ArrayList<>();
        if (inputBillBo.getType().equals(InputBillTypeEnum.余料入库.getValue())) {
            inputBillBo.getInputBillDetails().stream().forEach(details -> {
                //拼装原料接收对象
                MaterialStoreSignBoxDto storeSignBoxDto = new MaterialStoreSignBoxDto();
                storeSignBoxDto.setProductBatchNo(details.getBatchNo());
                storeSignBoxDto.setMaterialCode(details.getMaterialModelCode());
                storeSignBoxDto.setMaterialName(details.getMaterialModelName());
                storeSignBoxDto.setCreateUser(BaseContextHandler.getUsername());
                storeSignBoxDto.setUpdateUser(BaseContextHandler.getUsername());
                storeSignBoxDto.setWeight(details.getWeight());
                storeSignBoxDto.setMaterialBoxNo(details.getMaterialBoxNo());
                storeSignBoxDto.setMaterialLevel(details.getMaterialLevel());
                storeSignBoxDto.setMaterialModel(details.getMaterialModel());
                storeSignBoxDto.setMaterialGear(details.getMaterialGear());
                storeSignBoxDto.setBoxNo(details.getBoxNo());
                storeSignBoxDto.setPickingStatus(0);
                storeSignBoxDto.setMaterialType(2);
                storeSignBoxDto.setSupplier(details.getSupplier());
                storeSignBoxDto.setSupplierCode(details.getSupplierCode());
                storeSignBoxDto.setAufnr(details.getWorkOrderNo());
                storeSignBoxDto.setDateProduceBatchNo(details.getDateProduceBatchNo());
                storeSignBoxDtos.add(storeSignBoxDto);
            });
        }
        if (inputBillBo.getAutomaticOut()) {
            WarehouseOutputBill warehouseOutputBill = new WarehouseOutputBill();
            warehouseOutputBill.setType(inputBillBo.getType().equals(InputBillTypeEnum.余料入库.getValue())
                    ? OutputBillTypeEnum.余料出库.getValue() : inputBillBo.getType());
            warehouseOutputBill.setRemark(inputBillBo.getRemark());
            warehouseOutputBill.setDestination(OutputDestinationEnum.车间.getValue());
            warehouseOutputBill.setAutoAudit(true);
            warehouseOutputBill.setCreateTime(new Date());
            warehouseOutputBill.setCreateUserName(BaseContextHandler.getUsername());
            warehouseOutputBill.setStatus("0");
            warehouseOutputBill.setInputBillCode(inputBillNo);
            inputBillBo.getInputBillDetails().stream().forEach(details -> {
                WarehouseOutputBillDetail detail = new WarehouseOutputBillDetail();
                BeanUtils.copyProperties(details, detail);
                detail.setOutputCount(details.getCount());
                detail.setRequireCount(details.getCount());
                detail.setQuantity(details.getCount());
                detail.setCreateUserId(BaseContextHandler.getUserID());
                detail.setCreateUserName(BaseContextHandler.getUsername());
                detail.setCreateTime(new Date());
                detail.setType(inputBillBo.getType().equals(InputBillTypeEnum.余料入库.getValue())
                        ? OutputBillTypeEnum.余料出库.getValue() : inputBillBo.getType());
                detail.setStatus("已出库");
                detail.setDestination(OutputDestinationEnum.车间.getValue());
                warehouseOutputBill.getOutputBillDetails().add(detail);
            });
            String outputBillNos = warehouseOutputBillService.saveOutputBills(warehouseOutputBill);
            if (ObjectUtils.isEmpty(outputBillNos)) {
                return ResultGenerator.fail("生成出库单失败");
            }
        }
        if (!inputBillBo.getType().equals(InputBillTypeEnum.余料入库.getValue())) {
            //生成入库单及明细
            inputBillNo = warehouseInputBillService.saveInputBills(warehouseInputBill);
            if (!ObjectUtils.isEmpty(inputBillNo)) {
                return ResultGenerator.success("成功", inputBillNo);
            } else {
                return ResultGenerator.fail(result.getMessage());
            }
        } else {
            //生成入库单及明细
            inputBillNo = warehouseInputBillService.saveInputBills(warehouseInputBill);
            if (!ObjectUtils.isEmpty(inputBillNo)) {
                //调用原料接收接口
                result = materialCleanFeignClients.create(storeSignBoxDtos.get(0));
                if (result.getCode() != ResultCode.SUCCESS.getCode()) {
                    throw new BusinessException("调用清洗硅料创建:[materialStoreSignBox/create]失败: " + result.getMessage());
                }
            } else {
                return ResultGenerator.fail(result.getMessage());
            }
        }
        return ResultGenerator.success("成功", inputBillNo);
    }

    @Override
    public WarehouseInventoryDto getByBatchWarehouseId(String batchNo, Long warehouseId) {
        WarehouseInventory byBatchWarehouseId = warehouseInventoryService.getByBatchWarehouseId(batchNo, warehouseId);
        WarehouseInventoryDto warehouseInventoryDto = new WarehouseInventoryDto();
        BeanUtils.copyProperties(byBatchWarehouseId, warehouseInventoryDto);
        return warehouseInventoryDto;
    }

    @Override
    public List<String> findBatchNoBySerialNoOrTraceId(String serialNo, String traceId) {
        List<String> batchNos = new ArrayList<>();
        List<WarehouseInputBillDetail> warehouseInputBillDetails = warehouseInputBillDetailService.findBatchNoBySerialNoOrTraceId(serialNo, traceId);
        warehouseInputBillDetails.stream().forEach(entity -> {
            List<WarehouseInventory> warehouseInventories = inventoryService.getByMaterialAndBatchNoAndWarehouseCodes(entity.getBatchNo(), entity.getMaterialModelCode(), null);
            if (ObjectUtils.isNotEmpty(warehouseInventories) && warehouseInventories.size() > 0) {
                batchNos.add(entity.getBatchNo());
            }
        });
        return batchNos;
//        return warehouseInventoryService.findBatchNoBySerialNoOrTraceId(serialNo, traceId);
    }

    @Override
    public List<WarehouseInputBillDetailBo> findWarehouseInputBillDetailsByMaterialCode(String materialCode) {
        //fixme 这里查询input的record明细表
        List<WarehouseInputRecordBillDetail> list = warehouseInputRecordBillDetailService.findWarehouseInputRecordBillDetailsByMaterialCode(materialCode);
        return list.stream()
                .map(this::toLazyDto)
                .collect(Collectors.toList());
    }

    @Override
    public List<WarehouseInventoryDto> findWarehouseInventoryByMaterialCode(String materialCode) {
        return inventoryService.findWarehouseInventoryByMaterialCode(materialCode);
    }

    @Override
    public List<WarehouseOutputBillDetailBo> findWarehouseOutputBillDetailByMaterialCode(String materialCode) {
        //fixme 这里要查record明细表
        List<WarehouseOutputRecordBillDetail> list = warehouseOutputRecordBillDetailService.findWarehouseOutputRecordBillDetailByMaterialCode(materialCode);
        return list.stream()
                .map(this::toLazyDto)
                .collect(Collectors.toList());
    }

    @Override
    public Set<String> getDistinctMaterialCode(int page, int pageSize) {
        return warehouseInputBillDetailService.getDistinctMaterialCode(page, pageSize);
    }

    /**
     * @param storeDto 线边仓对象
     * @return
     */
    @Override
    @Transactional
    public Result createInputAndAllotAndOut(StoreDto storeDto) {
        try {
            if (ObjectUtils.isNotEmpty(storeDto)) {
                //执行入库逻辑
                if (ObjectUtils.isNotEmpty(storeDto.getInputBillBo())) {
                    input(storeDto.getInputBillBo());
                }
                //执行调拨逻辑
                if (ObjectUtils.isNotEmpty(storeDto.getWarehouseAllotBillDto())) {
                    createAllotBill(storeDto.getWarehouseAllotBillDto());
                }
                //执行出库逻辑
                if (ObjectUtils.isNotEmpty(storeDto.getOutputBillBo())) {
                    output(storeDto.getOutputBillBo());
                }
            }
        } catch (Exception e) {
            throw new BusinessException("调用创建线边仓流程单据接口失败:" + e.getMessage());
        }
        return ResultGenerator.success();
    }

    /**
     * 同步物料主数据
     *
     * @param warehouseMaterialBos
     */
    @Override
    @Transactional
    public Result syncMaterial(List<WarehouseMaterialBo> warehouseMaterialBos) {
        //log.error("receive data from mes, code:{}", warehouseMaterialBos.get(0).getMaterialCode());
        for (WarehouseMaterialBo warehouseMaterialBo : warehouseMaterialBos) {
            boolean result;
            WarehouseMaterial warehouseMaterial = warehouseMaterialService.getMaterialByMaterialCode(warehouseMaterialBo.getMaterialCode());

            if (warehouseMaterial == null) {
                warehouseMaterial = new WarehouseMaterial();
                warehouseMaterial.setMaterialId(warehouseMaterialBo.getMaterialId());
                warehouseMaterial.setMaterialCode(warehouseMaterialBo.getMaterialCode());
                warehouseMaterial.setMaterialName(warehouseMaterialBo.getMaterialName());
                warehouseMaterial.setCreateTime(new Date());
                warehouseMaterial.setCreateUserId(BaseContextHandler.getUserID());
                warehouseMaterial.setCreateUserName(BaseContextHandler.getUsername());
                //更新线边仓相关数据
                buildWarehouseDetail(warehouseMaterial);
                result = warehouseMaterialService.save(warehouseMaterial);
            } else {
                warehouseMaterial.setMaterialId(warehouseMaterialBo.getMaterialId());
                warehouseMaterial.setMaterialCode(warehouseMaterialBo.getMaterialCode());
                warehouseMaterial.setMaterialName(warehouseMaterialBo.getMaterialName());
                if (warehouseMaterialBo.isUpdateMaterial()) {
                    //更新线边仓库位相关数据
                    buildWarehouseLocation(warehouseMaterial);
                }
                result = warehouseMaterialService.updateById(warehouseMaterial);
            }
            if (!result) {
                log.error("insert or update data error, code:{}", warehouseMaterial.getMaterialCode());
            }
            //log.error("id:{} 处理结果：{}", warehouseMaterialBo.getMaterialCode(), result);
        }
        return ResultGenerator.success();
    }

    /**
     * 更新物料数据时，同步一下默认值，默认关闭，仅修复数据时使用
     *
     * @param warehouseMaterial
     */
    private void buildWarehouseLocation(WarehouseMaterial warehouseMaterial) {
        Result<DictionaryItemDto> nameByThemeValueAndItemValue = ybFeignClients.findByThemeCodeAndItemName("syncMaterialDefaultLocationCode", "warehouseDefaultLocation");
        if (ObjectUtils.isNotEmpty(nameByThemeValueAndItemValue) && nameByThemeValueAndItemValue.getCode().equals(200)) {
            WarehouseModel warehouseModel = warehouseModelService.getCode(nameByThemeValueAndItemValue.getData().getValue());
            if (ObjectUtils.isNotEmpty(warehouseModel)) {
                warehouseMaterial.setDefaultLocationId(warehouseModel.getId());
                warehouseMaterial.setDefaultLocationCode(warehouseModel.getCode());
                warehouseMaterial.setDefaultLocation(warehouseModel.getName());
            }
        }
    }

    /**
     * 新增同步物料数据时：设置默认值
     *
     * @param warehouseMaterial
     */
    private void buildWarehouseDetail(WarehouseMaterial warehouseMaterial) {
        warehouseMaterial.setLowerLimit(new BigDecimal(1));
        warehouseMaterial.setUpperLimit(new BigDecimal(1000000));
        Result<DictionaryItemDto> nameByThemeValueAndItemValue = ybFeignClients.findByThemeCodeAndItemName("syncMaterialDefaultLocationCode", "warehouseDefaultLocation");
        if (ObjectUtils.isNotEmpty(nameByThemeValueAndItemValue) && nameByThemeValueAndItemValue.getCode().equals(200)) {
            WarehouseModel warehouseModel = warehouseModelService.getCode(nameByThemeValueAndItemValue.getData().getValue());
            if (ObjectUtils.isNotEmpty(warehouseModel)) {
                warehouseMaterial.setDefaultLocationId(warehouseModel.getId());
                warehouseMaterial.setDefaultLocationCode(warehouseModel.getCode());
                warehouseMaterial.setDefaultLocation(warehouseModel.getName());
            }
        }
        warehouseMaterial.setBatch(true);
        warehouseMaterial.setUniqueCode(false);
        warehouseMaterial.setSafetyStock("1-100");
    }

    @Override
    public WarehouseModel getById(Long id) {
        return warehouseModelMapper.findById(id);
    }

    @Override
    public List<WarehouseModelDto> getChildLocationIds(Long parentId) {
        List<WarehouseModelDto> storeLocations = new ArrayList<WarehouseModelDto>();
        addChild(storeLocations, parentId);
        return storeLocations;
    }

    /**
     * 递归查询库位子节点
     *
     * @param storeLocations
     * @param parentId
     */
    private void addChild(List<WarehouseModelDto> storeLocations, Long parentId) {
        List<WarehouseModel> children = warehouseModelMapper.findByParentId(parentId);
        if (CollectionUtils.isEmpty(children)) {
            return;
        }
        for (WarehouseModel warehouseModel : children) {
            WarehouseModelDto warehouseModelDto = modelMapper.map(warehouseModel, WarehouseModelDto.class);
            //查询所属厂区
            Long factoryId = warehouseModel.getFactoryId();
            WarehouseModel factory = warehouseModelMapper.findById(factoryId);
            if (factory != null) {
                warehouseModelDto.setFactoryName(factory.getName());
            }
            //查询所属仓库
            Long warehouseId = warehouseModel.getWarehouseId();
            WarehouseModel warehouse = warehouseModelMapper.findById(warehouseId);
            if (warehouse != null) {
                warehouseModelDto.setWarehouseName(warehouse.getName());
            }
            //查询所属库区
            Long areaId = warehouseModel.getAreaId();
            WarehouseModel area = warehouseModelMapper.findById(areaId);
            if (area != null) {
                warehouseModelDto.setAreaName(area.getName());
            }
            storeLocations.add(warehouseModelDto);
            addChild(storeLocations, warehouseModel.getId());
        }
    }

    /**
     * 线边仓回滚接口
     *
     * @param bo
     * @return
     */
    @Override
    @Transactional
    public Result rollBackStore(StoreDataBo bo) {
        try {
            //入库
            if (bo.getReturnType().equals(StoreBillTypeEnum.INPUT.getType())) {
                WarehouseInputBillDto warehouseInputBillDto = new WarehouseInputBillDto();
                List<WarehouseInputBillDetailDto> inputBillDetails = new ArrayList<>();
                BeanUtils.copyProperties(bo,warehouseInputBillDto);
                bo.getDetailsBos().forEach(entity->{
                    WarehouseInputBillDetailDto warehouseInputBillDetailDto = new WarehouseInputBillDetailDto();
                    BeanUtils.copyProperties(entity,warehouseInputBillDetailDto);
                    inputBillDetails.add(warehouseInputBillDetailDto);
                });
                warehouseInputBillDto.setInputBillDetails(inputBillDetails);
                warehouseInputBillService.saveInputBills(warehouseInputBillDto);
            }
            //出库
            if (bo.getReturnType().equals(StoreBillTypeEnum.OUTPUT.getType())) {
                WarehouseOutputBill warehouseOutputBill = new WarehouseOutputBill();
                List<WarehouseOutputBillDetail> outputBillDetails = new ArrayList<>();
                BeanUtils.copyProperties(bo,warehouseOutputBill);
                bo.getDetailsBos().forEach(entity->{
                    WarehouseOutputBillDetail warehouseOutputBillDetail = new WarehouseOutputBillDetail();
                    BeanUtils.copyProperties(entity,warehouseOutputBillDetail);
                    outputBillDetails.add(warehouseOutputBillDetail);
                });
                warehouseOutputBill.setOutputBillDetails(outputBillDetails);
                warehouseOutputBillService.saveOutputBills(warehouseOutputBill);
            }
            //调拨
            if (bo.getReturnType().equals(StoreBillTypeEnum.ALLOT.getType())) {
                WarehouseAllotBillDto warehouseAllotBillDto = new WarehouseAllotBillDto();
                List<WarehouseAllotBillDetailDto> allotBillDetailDtos = new ArrayList<>();
                BeanUtils.copyProperties(bo,warehouseAllotBillDto);
                warehouseAllotBillDto.setAllotType(bo.getType());
                bo.getDetailsBos().forEach(entity->{
                    WarehouseAllotBillDetailDto warehouseAllotBillDetailDto = new WarehouseAllotBillDetailDto();
                    BeanUtils.copyProperties(entity,warehouseAllotBillDetailDto);
                    allotBillDetailDtos.add(warehouseAllotBillDetailDto);
                });
                warehouseAllotBillDto.setAllotBillDetailDtos(allotBillDetailDtos);
                warehouseAllotBillService.create(warehouseAllotBillDto);
            }
        } catch (Exception ex) {
            return ResultGenerator.fail("数据回滚失败,失败原因:" + JSON.parse(ex.getMessage()));
        }
        return ResultGenerator.success();
    }

    public WarehouseOutputBillDetailBo toLazyDto(WarehouseOutputRecordBillDetail entity) {
        return modelMapper.map(entity, WarehouseOutputBillDetailBo.class);
    }

    public WarehouseInputBillDetailBo toLazyDto(WarehouseInputRecordBillDetail entity) {
        return modelMapper.map(entity, WarehouseInputBillDetailBo.class);
    }
}
