package com.hw.wms.service.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

import com.hw.common.core.constant.SecurityConstants;
import com.hw.common.core.constant.WmsConstants;
import com.hw.common.core.domain.R;
import com.hw.common.core.exception.ServiceException;
import com.hw.common.core.utils.uuid.Seq;
import com.hw.common.security.utils.SecurityUtils;
import com.hw.mes.api.RemoteMesService;
import com.hw.mes.api.domain.MesBaseBarcodeInfo;
import com.hw.wms.config.WmsConfig;
import com.hw.wms.domain.*;
import com.hw.wms.domain.vo.WmsProduceInstockVo;
import com.hw.wms.domain.vo.WmsProductInstockVo;
import com.hw.wms.domain.vo.WmsRawInstockVo;
import com.hw.wms.mapper.WmsBaseLocationMapper;
import com.hw.wms.mapper.WmsProductInstockDetailMapper;
import com.hw.wms.mapper.WmsProductStockMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.stream.Collectors;

import com.hw.common.core.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.hw.wms.mapper.WmsProductInstockMapper;
import com.hw.wms.service.IWmsProductInstockService;

import javax.annotation.Resource;

/**
 * 成品入库记录;成品入库记录Service业务层处理
 *
 * @author xins
 * @date 2023-12-25
 */
@Service
public class WmsProductInstockServiceImpl implements IWmsProductInstockService {
    @Autowired
    private WmsProductInstockMapper wmsProductInstockMapper;

    @Autowired
    private WmsProductInstockDetailMapper wmsProductInstockDetailMapper;

    @Autowired
    private WmsProductStockMapper wmsProductStockMapper;

    @Autowired
    private WmsBaseLocationMapper wmsBaseLocationMapper;

    @Autowired
    private WmsConfig wmsConfig;

    @Resource
    private RemoteMesService remoteMesService;


    /**
     * 查询成品入库记录;成品入库记录
     *
     * @param productInstockId 成品入库记录;成品入库记录主键
     * @return 成品入库记录;成品入库记录
     */
    @Override
    public WmsProductInstock selectWmsProductInstockByProductInstockId(Long productInstockId) {
        return wmsProductInstockMapper.selectWmsProductInstockByProductInstockId(productInstockId);
    }

    /**
     * 查询成品入库记录;成品入库记录列表
     *
     * @param wmsProductInstock 成品入库记录;成品入库记录
     * @return 成品入库记录;成品入库记录
     */
    @Override
    public List<WmsProductInstock> selectWmsProductInstockList(WmsProductInstock wmsProductInstock) {
        return wmsProductInstockMapper.selectWmsProductInstockList(wmsProductInstock);
    }

    /**
     * 新增成品入库记录;成品入库记录
     *
     * @param wmsProductInstock 成品入库记录;成品入库记录
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertWmsProductInstock(WmsProductInstock wmsProductInstock) {
        int rows = wmsProductInstockMapper.insertWmsProductInstock(wmsProductInstock);
        insertWmsProductInstockDetail(wmsProductInstock);
        return rows;
    }

    /**
     * 修改成品入库记录;成品入库记录
     *
     * @param wmsProductInstock 成品入库记录;成品入库记录
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateWmsProductInstock(WmsProductInstock wmsProductInstock) {
        wmsProductInstockMapper.deleteWmsProductInstockDetailByProductInstockId(wmsProductInstock.getProductInstockId());
        insertWmsProductInstockDetail(wmsProductInstock);
        return wmsProductInstockMapper.updateWmsProductInstock(wmsProductInstock);
    }

    /**
     * 批量删除成品入库记录;成品入库记录
     *
     * @param productInstockIds 需要删除的成品入库记录;成品入库记录主键
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int deleteWmsProductInstockByProductInstockIds(Long[] productInstockIds) {
        wmsProductInstockMapper.deleteWmsProductInstockDetailByProductInstockIds(productInstockIds);
        return wmsProductInstockMapper.deleteWmsProductInstockByProductInstockIds(productInstockIds);
    }

    /**
     * 删除成品入库记录;成品入库记录信息
     *
     * @param productInstockId 成品入库记录;成品入库记录主键
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int deleteWmsProductInstockByProductInstockId(Long productInstockId) {
        wmsProductInstockMapper.deleteWmsProductInstockDetailByProductInstockId(productInstockId);
        return wmsProductInstockMapper.deleteWmsProductInstockByProductInstockId(productInstockId);
    }

    /**
     * 新增成品入库记录明细信息
     *
     * @param wmsProductInstock 成品入库记录;成品入库记录对象
     */
    public void insertWmsProductInstockDetail(WmsProductInstock wmsProductInstock) {
        List<WmsProductInstockDetail> wmsProductInstockDetailList = wmsProductInstock.getWmsProductInstockDetailList();
        Long productInstockId = wmsProductInstock.getProductInstockId();
        if (StringUtils.isNotNull(wmsProductInstockDetailList)) {
            List<WmsProductInstockDetail> list = new ArrayList<WmsProductInstockDetail>();
            for (WmsProductInstockDetail wmsProductInstockDetail : wmsProductInstockDetailList) {
                wmsProductInstockDetail.setProductInstockId(productInstockId);
                list.add(wmsProductInstockDetail);
            }
            if (list.size() > 0) {
                wmsProductInstockMapper.batchWmsProductInstockDetail(list);
            }
        }
    }


    /**
     * 新增成品入库记录(适用于移动手持端，适用于5楼成品入库)
     *
     * @param wmsProductInstockVo 原材料入库记录
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertWmsProductInstock(WmsProductInstockVo wmsProductInstockVo) {
        String materialBarcode = wmsProductInstockVo.getMaterialBarcode();
        R<MesBaseBarcodeInfo> baseBarcodeInfoR = remoteMesService.getBarcode(materialBarcode, SecurityConstants.INNER);
        MesBaseBarcodeInfo baseBarcodeInfo = baseBarcodeInfoR.getData();
        if (baseBarcodeInfo == null) {
            throw new ServiceException("物料编码有误");
        }
        Long productId = baseBarcodeInfo.getMaterialId();

        String locationCode = wmsProductInstockVo.getLocationCode();
        WmsBaseLocation baseLocation = wmsBaseLocationMapper.selectWmsBaseLocationByLocationCode(locationCode);
        if (baseLocation == null) {
            throw new ServiceException("库位编码有误");
        }
        //todo 仓库可存储此物料判断是否可以入此库位

        Date currentDate = new Date();
        String userName = SecurityUtils.getUsername();
        WmsProductInstock wmsProductInstock = new WmsProductInstock();
        wmsProductInstock.setWarehouseId(baseLocation.getWarehouseId());
        wmsProductInstock.setLocationCode(locationCode);
        wmsProductInstock.setProductType(WmsConstants.PRODUCT_INSTOCK_STOCK_TYPE_PRODUCT);
        wmsProductInstock.setOperationType(WmsConstants.WMS_OPERATION_TYPE_MANUAL);
        wmsProductInstock.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_FINISH);
        wmsProductInstock.setPlanCode(baseBarcodeInfo.getPlanCode());
        wmsProductInstock.setPlanDetailCode(baseBarcodeInfo.getPlanDetailCode());
        wmsProductInstock.setProductBatch(materialBarcode);
        wmsProductInstock.setProductId(productId);
        wmsProductInstock.setInstockType(WmsConstants.PRODUCT_INSTOCK_INSTOCK_TYPE_PRODUCT);
        wmsProductInstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
        wmsProductInstock.setInstockAmount(BigDecimal.ONE);
        wmsProductInstock.setApplyBy(userName);
        wmsProductInstock.setApplyDate(currentDate);

        //插入记录
        int rows = wmsProductInstockMapper.insertWmsProductInstock(wmsProductInstock);

        //插入明细
//        insertWmsProductInstockDetail(wmsProductInstock, materialBarcode, productId, wmsProductInstockVo);

        //更新库存
        updateProductStock(baseBarcodeInfo, locationCode, baseLocation.getWarehouseId(), baseLocation.getWarehouseFloor(), userName, currentDate);

        return rows;
    }


    /**
     * 插入成品入库明细，手持成品入库使用。适用于4楼成品入库
     *
     * @param wmsProductInstock
     * @param materialBarcode
     * @param productId
     * @param wmsProductInstockVo
     */
    public void insertWmsProductInstockDetail(WmsProductInstock wmsProductInstock, String materialBarcode, Long productId, WmsProductInstockVo wmsProductInstockVo) {
        WmsProductInstockDetail wmsProductInstockDetail = new WmsProductInstockDetail();
        wmsProductInstockDetail.setProductInstockId(wmsProductInstock.getProductInstockId());
        wmsProductInstockDetail.setLocationCode(wmsProductInstock.getLocationCode());
        wmsProductInstockDetail.setProductBarcode(materialBarcode);
        wmsProductInstockDetail.setProductId(productId);
        wmsProductInstockDetail.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_FINISH);
        wmsProductInstockDetail.setInstockBy(wmsProductInstock.getApplyBy());
        wmsProductInstockDetail.setInstockDate(wmsProductInstock.getApplyDate());
        wmsProductInstockDetail.setInstockWay(WmsConstants.PRODUCT_INSTOCK_INSTOCK_WAY_MANUAL);
        wmsProductInstockDetail.setPlanAmount(new BigDecimal(1));
        wmsProductInstockDetail.setInstockAmount(new BigDecimal(1));
        wmsProductInstockDetailMapper.insertWmsProductInstockDetail(wmsProductInstockDetail);
    }


    /**
     * 更新成品库存,适合于五楼PDA扫描成品入库
     *
     * @param baseBarcodeInfo
     * @param locationCode
     * @param warehouseId
     * @param warehouseFloor
     * @param userName
     * @param currentDate
     */
    public void updateProductStock(MesBaseBarcodeInfo baseBarcodeInfo, String locationCode, Long warehouseId, Long warehouseFloor,
                                   String userName, Date currentDate) {

        BigDecimal instockAmount = new BigDecimal(1);
        //判断此库位的数量限制，是否还能入库
//            WmsProductStock queryProductStock = new WmsProductStock();
//            queryProductStock.setLocationCode(locationCode);
//            BigDecimal totalAmount = wmsProductStockMapper.getProductStockTotalAmount(queryProductStock);
//            totalAmount = totalAmount == null ? BigDecimal.ZERO : totalAmount;
//            if (totalAmount.add(instockAmount).compareTo(baseLocation.getQtyLimit()) > 0) {
//                throw new ServiceException("已超出库位数量限制，请重新选择库位");
//            }
        String materialBarcode = baseBarcodeInfo.getBarcodeInfo();
        WmsProductStock queryProductStock = new WmsProductStock();
        queryProductStock.setProductBatch(materialBarcode);
        WmsProductStock productStock = wmsProductStockMapper.selectProductStockByBatch(materialBarcode);
        if (productStock != null) {
            throw new ServiceException("此成品已经入库，无需重复入库");
        }

        //一个成品一个条码，对应一条库存信息
        WmsProductStock wmsProductStock = new WmsProductStock();
        wmsProductStock.setWarehouseId(warehouseId);
        wmsProductStock.setLocationCode(locationCode);
        wmsProductStock.setStockType(WmsConstants.PRODUCT_STOCK_STOCK_TYPE_PRODUCT);
        wmsProductStock.setProductId(baseBarcodeInfo.getMaterialId());
        wmsProductStock.setProductBatch(materialBarcode);
        wmsProductStock.setPlanCode(baseBarcodeInfo.getPlanCode());
        wmsProductStock.setPlanDetailCode(baseBarcodeInfo.getPlanDetailCode());
        wmsProductStock.setWarehouseFloor(warehouseFloor);
        wmsProductStock.setSaleorderCode(baseBarcodeInfo.getSaleorderCode());
//            wmsProductStock.setQualityStatus(wmsRawInstockVo.getQualityStatus());
        wmsProductStock.setTotalAmount(instockAmount);
        wmsProductStock.setCreateBy(userName);
        wmsProductStock.setCreateDate(currentDate);
        wmsProductStock.setInstockDate(currentDate);
        wmsProductStockMapper.insertWmsProductStock(wmsProductStock);

    }

    /**
     * 生产入库，适合在五楼背板安装区（将组装好的柜体入到半成品库）
     *
     * @param wmsProduceInstockVo
     * @return
     */
    @Override
    public int fifthFloorProduceInstock(WmsProduceInstockVo wmsProduceInstockVo) {
        Long warehouseId = wmsConfig.getFifthSemiWarehouseId();//五楼半成品库
        String productType = WmsConstants.PRODUCT_STOCK_STOCK_TYPE_SEMI;
        String operationType = WmsConstants.WMS_OPERATION_TYPE_AUTO;
        String executeStatus = WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE;

        return produceInstock(wmsProduceInstockVo, warehouseId, productType, operationType, executeStatus, 5L);
    }

    /**
     * 新增成品入库记录(适用于Web端，适用于1楼成品入库，入虚拟库，无库位)
     *
     * @param wmsProduceInstockVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int firstFloorProduceInstock(WmsProduceInstockVo wmsProduceInstockVo) {
        Long warehouseId = wmsConfig.getFirstFloorProductWarehouseId();
        String productType = WmsConstants.PRODUCT_INSTOCK_STOCK_TYPE_PRODUCT;
        String operationType = WmsConstants.WMS_OPERATION_TYPE_MANUAL;
        String executeStatus = WmsConstants.WMS_EXECUTE_STATUS_FINISH;
        return produceInstock(wmsProduceInstockVo, warehouseId, productType, operationType, executeStatus, 1L);
    }


    /**
     * 新增成品入库记录(适用于Web端，适用于4楼成品入库，入虚拟库，无库位)
     *
     * @param wmsProduceInstockVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int fourthFloorProduceInstock(WmsProduceInstockVo wmsProduceInstockVo) {
        Long warehouseId = wmsConfig.getFourthFloorProductWarehouseId();
        String productType = WmsConstants.PRODUCT_INSTOCK_STOCK_TYPE_PRODUCT;
        String operationType = WmsConstants.WMS_OPERATION_TYPE_MANUAL;
        String executeStatus = WmsConstants.WMS_EXECUTE_STATUS_FINISH;
        return produceInstock(wmsProduceInstockVo, warehouseId, productType, operationType, executeStatus, 4L);
    }


    /**
     * 新增成品入库记录
     *
     * @param wmsProduceInstockVo
     * @param warehouseId
     * @param productType
     * @param operationType
     * @param executeStatus
     * @return
     */
    public int produceInstock(WmsProduceInstockVo wmsProduceInstockVo, Long warehouseId, String productType, String operationType, String executeStatus, Long warehouseFloor) {
        String materialBarcode = wmsProduceInstockVo.getMaterialBarcode();
        R<MesBaseBarcodeInfo> baseBarcodeInfoR = remoteMesService.getBarcode(materialBarcode, SecurityConstants.INNER);
        if (baseBarcodeInfoR == null) {
            throw new ServiceException("物料编码有误");
        }
        MesBaseBarcodeInfo baseBarcodeInfo = baseBarcodeInfoR.getData();
        if (baseBarcodeInfo == null) {
            throw new ServiceException("物料编码有误");
        }

        if (baseBarcodeInfo.getBarcodeType().equals(WmsConstants.RWA_STOCK_STOCK_TYPE_RAW)) {
            throw new ServiceException("此物料条码为原材料，非成品条码");
        }

        //如果执行状态不是已完成，是agv入库，则需要判断是否有入库记录，避免重复提交；如果执行状态是已完成（人工入库），则判断是否有此成品条码库存即可
        if (!executeStatus.equals(WmsConstants.WMS_EXECUTE_STATUS_FINISH)) {
            WmsProductInstock queryProductInstock = new WmsProductInstock();
            queryProductInstock.setProductBatch(materialBarcode);//productbatch是索引，查出来再过滤性能更快
            List<WmsProductInstock> wmsProductInstocks = wmsProductInstockMapper.selectWmsProductInstockList(queryProductInstock);
            if (wmsProductInstocks != null && !wmsProductInstocks.isEmpty()) {
                List<WmsProductInstock> incompleteProductInstocks = wmsProductInstocks.stream().filter(
                        wmsProductInstock -> !wmsProductInstock.getExecuteStatus().equals(WmsConstants.WMS_EXECUTE_STATUS_FINISH)).collect(Collectors.toList());
                if (incompleteProductInstocks != null && !incompleteProductInstocks.isEmpty()) {
                    throw new ServiceException("已经有此成品入库记录");
                }
            }
        }

        String userName = SecurityUtils.getUsername();
        Date currentDate = new Date();
        WmsProductInstock wmsProductInstock = new WmsProductInstock();
        wmsProductInstock.setTaskCode(Seq.getId(Seq.productInstockSeqType, Seq.productInstockCode));
        wmsProductInstock.setWarehouseId(warehouseId);
        wmsProductInstock.setPalletInfoCode(baseBarcodeInfo.getPalletInfoCode());
        wmsProductInstock.setProductType(productType);
        wmsProductInstock.setOperationType(operationType);
        wmsProductInstock.setPlanCode(baseBarcodeInfo.getPlanCode());
        wmsProductInstock.setPlanDetailCode(baseBarcodeInfo.getPlanDetailCode());
        wmsProductInstock.setInstockType(WmsConstants.PRODUCT_INSTOCK_INSTOCK_TYPE_PRODUCT);
        wmsProductInstock.setProductId(baseBarcodeInfo.getMaterialId());
        wmsProductInstock.setProductBatch(materialBarcode);
        wmsProductInstock.setInstockAmount(BigDecimal.ONE);
        wmsProductInstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
        wmsProductInstock.setExecuteStatus(executeStatus);
        wmsProductInstock.setApplyBy(userName);
        wmsProductInstock.setApplyDate(currentDate);

        if (executeStatus.equals(WmsConstants.WMS_EXECUTE_STATUS_FINISH)) {
            updateProductStock(baseBarcodeInfo, "", warehouseId, warehouseFloor, userName, currentDate);
        }
        return wmsProductInstockMapper.insertWmsProductInstock(wmsProductInstock);
    }

    public void syncToErp() {
        //todo 根据质检状态是通过的同步给ERP
    }

}
