package com.hw.wms.service.impl;

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

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.mes.api.domain.MesBaseMaterialInfo;
import com.hw.mes.api.domain.vo.MesBaseMaterialInfoVo;
import com.hw.wms.domain.*;
import com.hw.wms.domain.vo.WmsRawOutstockAuditVo;
import com.hw.wms.domain.vo.WmsRawOutstockConfirmVo;
import com.hw.wms.domain.vo.WmsRawReturnAuditVo;
import com.hw.wms.domain.vo.WmsRawReturnConfirmVo;
import com.hw.wms.mapper.WmsRawReturnDetailMapper;
import com.hw.wms.mapper.WmsRawStockMapper;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.stream.Collectors;

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

import javax.annotation.Resource;

/**
 * 原材料退库记录Service业务层处理
 *
 * @author xs
 * @date 2023-12-20
 */
@Service
public class WmsRawReturnServiceImpl implements IWmsRawReturnService {
    @Autowired
    private WmsRawReturnMapper wmsRawReturnMapper;

    @Autowired
    private WmsRawReturnDetailMapper wmsRawReturnDetailMapper;

    @Autowired
    private WmsRawStockMapper wmsRawStockMapper;

    @Resource
    private RemoteMesService remoteMesService;

    /**
     * 查询原材料退库记录，退库审核使用
     *
     * @param rawReturnId 原材料退库记录主键
     * @return 原材料退库记录
     */
    @Override
    public WmsRawReturn selectWmsRawReturnByRawReturnId(Long rawReturnId) {
        WmsRawReturn rawReturn = wmsRawReturnMapper.selectOnlyWmsRawReturnByRawReturnId(rawReturnId);
        Long materialId = rawReturn.getMaterialId() == null ? 0L : rawReturn.getMaterialId();
        Long productId = rawReturn.getProductId() == null ? 0L : rawReturn.getProductId();
        Long[] materialIds = {materialId, productId};
        MesBaseMaterialInfoVo mesBaseMaterialInfoVo = new MesBaseMaterialInfoVo();
        mesBaseMaterialInfoVo.setMaterialIds(materialIds);
        R<List<MesBaseMaterialInfo>> materialInfosR = remoteMesService.getMaterialsByMaterialIds(mesBaseMaterialInfoVo, SecurityConstants.INNER);
        if (materialInfosR != null) {
            List<MesBaseMaterialInfo> materialInfos = materialInfosR.getData();

            Map<Long, MesBaseMaterialInfo> mesBaseMaterialInfoMap = materialInfos.stream()
                    .collect(Collectors.toMap(MesBaseMaterialInfo::getMaterialId, mesBaseMaterialInfo -> mesBaseMaterialInfo));

            MesBaseMaterialInfo materialInfo = mesBaseMaterialInfoMap.get(materialId);
            if (materialInfo != null) {
                rawReturn.setMaterialName(materialInfo.getMaterialName());
            }
            MesBaseMaterialInfo productInfo = mesBaseMaterialInfoMap.get(productId);
            if (productInfo != null) {
                rawReturn.setProductName(productInfo.getMaterialName());
            }
        }

        return rawReturn;

    }

    /**
     * 查询原材料退库记录，退库确认使用
     *
     * @param rawReturnId 原材料退库记录主键
     * @return 原材料退库记录
     */
    @Override
    public WmsRawReturn selectWmsRawReturnByRawReturnId4Confirm(Long rawReturnId) {
        WmsRawReturn rawReturn = wmsRawReturnMapper.selectWmsRawReturnByRawReturnId(rawReturnId);
        Long materialId = rawReturn.getMaterialId() == null ? 0L : rawReturn.getMaterialId();
        Long productId = rawReturn.getProductId() == null ? 0L : rawReturn.getProductId();
        Long[] rawReturnMaterialIds = {materialId, productId};

        List<WmsRawReturnDetail> wmsRawReturnDetailList = rawReturn.getWmsRawReturnDetailList();
        Long[] rawReturnDetailMaterialIds = wmsRawReturnDetailList.stream().map(o -> o.getMaterialId()).toArray(Long[]::new);
        Long[] materialIds = ArrayUtils.addAll(rawReturnMaterialIds, rawReturnDetailMaterialIds);

        if (materialIds.length > 0) {
            MesBaseMaterialInfoVo mesBaseMaterialInfoVo = new MesBaseMaterialInfoVo();
            mesBaseMaterialInfoVo.setMaterialIds(materialIds);
            R<List<MesBaseMaterialInfo>> materialInfosR = remoteMesService.getMaterialsByMaterialIds(mesBaseMaterialInfoVo, SecurityConstants.INNER);
            if (materialInfosR != null) {
                List<MesBaseMaterialInfo> materialInfos = materialInfosR.getData();

                Map<Long, MesBaseMaterialInfo> mesBaseMaterialInfoMap = materialInfos.stream()
                        .collect(Collectors.toMap(MesBaseMaterialInfo::getMaterialId, mesBaseMaterialInfo -> mesBaseMaterialInfo));
                MesBaseMaterialInfo materialInfo = mesBaseMaterialInfoMap.get(materialId);
                if (materialInfo != null) {
                    rawReturn.setMaterialName(materialInfo.getMaterialName());
                }
                MesBaseMaterialInfo productInfo = mesBaseMaterialInfoMap.get(productId);
                if (productInfo != null) {
                    rawReturn.setProductName(productInfo.getMaterialName());
                }

                wmsRawReturnDetailList.forEach(wmsRawReturnDetail -> {
                    MesBaseMaterialInfo detailMaterialInfo = mesBaseMaterialInfoMap.get(wmsRawReturnDetail.getMaterialId());
                    if (materialInfo != null) {
                        wmsRawReturnDetail.setMaterialCode(detailMaterialInfo.getMaterialCode());
                        wmsRawReturnDetail.setMaterialName(detailMaterialInfo.getMaterialName());
                    }
                });
            }

        }

        return rawReturn;

    }

    /**
     * 查询原材料退库记录列表
     *
     * @param wmsRawReturn 原材料退库记录
     * @return 原材料退库记录
     */
    @Override
    public List<WmsRawReturn> selectWmsRawReturnList(WmsRawReturn wmsRawReturn) {
        return wmsRawReturnMapper.selectWmsRawReturnList(wmsRawReturn);
    }

    /**
     * 新增原材料退库记录
     *
     * @param wmsRawReturn 原材料退库记录
     * @return 结果
     */
    @Transactional
    @Override
    public int insertWmsRawReturn(WmsRawReturn wmsRawReturn) {
        int rows = wmsRawReturnMapper.insertWmsRawReturn(wmsRawReturn);
        insertWmsRawReturnDetail(wmsRawReturn);
        return rows;
    }

    /**
     * 修改原材料退库记录
     *
     * @param wmsRawReturn 原材料退库记录
     * @return 结果
     */
    @Transactional
    @Override
    public int updateWmsRawReturn(WmsRawReturn wmsRawReturn) {
        wmsRawReturnMapper.deleteWmsRawReturnDetailByRawReturnId(wmsRawReturn.getRawReturnId());
        insertWmsRawReturnDetail(wmsRawReturn);
        return wmsRawReturnMapper.updateWmsRawReturn(wmsRawReturn);
    }

    /**
     * 批量删除原材料退库记录
     *
     * @param rawReturnIds 需要删除的原材料退库记录主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteWmsRawReturnByRawReturnIds(Long[] rawReturnIds) {
        wmsRawReturnMapper.deleteWmsRawReturnDetailByRawReturnIds(rawReturnIds);
        return wmsRawReturnMapper.deleteWmsRawReturnByRawReturnIds(rawReturnIds);
    }

    /**
     * 删除原材料退库记录信息
     *
     * @param rawReturnId 原材料退库记录主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteWmsRawReturnByRawReturnId(Long rawReturnId) {
        wmsRawReturnMapper.deleteWmsRawReturnDetailByRawReturnId(rawReturnId);
        return wmsRawReturnMapper.deleteWmsRawReturnByRawReturnId(rawReturnId);
    }

    /**
     * 新增原材料退库记录明细信息
     *
     * @param wmsRawReturn 原材料退库记录对象
     */
    public void insertWmsRawReturnDetail(WmsRawReturn wmsRawReturn) {
        List<WmsRawReturnDetail> wmsRawReturnDetailList = wmsRawReturn.getWmsRawReturnDetailList();
        Long rawReturnId = wmsRawReturn.getRawReturnId();
        if (StringUtils.isNotNull(wmsRawReturnDetailList)) {
            List<WmsRawReturnDetail> list = new ArrayList<WmsRawReturnDetail>();
            for (WmsRawReturnDetail wmsRawReturnDetail : wmsRawReturnDetailList) {
                wmsRawReturnDetail.setRawReturnId(rawReturnId);
                list.add(wmsRawReturnDetail);
            }
            if (list.size() > 0) {
                wmsRawReturnMapper.batchWmsRawReturnDetail(list);
            }
        }
    }


    /**
     * 查询原材料退库记录列表,供手持退库审核使用
     *
     * @param wmsRawReturn 原材料退库记录
     * @return 原材料退库记录
     */
    @Override
    public List<WmsRawReturn> selectWmsRawReturnJoinList(WmsRawReturn wmsRawReturn) {
        return wmsRawReturnMapper.selectWmsRawReturnJoinList(wmsRawReturn);
    }


    /**
     * 审核原材料退库记录
     *
     * @param wmsRawReturnAuditVo
     */
    @Override
    public int auditWmsRawReturn(WmsRawReturnAuditVo wmsRawReturnAuditVo) {
        String auditStatus = wmsRawReturnAuditVo.getAuditStatus();
        String auditReason = wmsRawReturnAuditVo.getAuditReason();
        if (WmsConstants.WMS_AUDIT_STATUS_FAIL.equals(auditStatus) && StringUtils.isEmpty(auditReason)) {
            throw new ServiceException("请输入审核意见");
        }

        WmsRawReturn wmsRawReturn = wmsRawReturnMapper.selectWmsRawReturnByRawReturnId(wmsRawReturnAuditVo.getRawReturnId());
        wmsRawReturn.setAuditStatus(auditStatus);
        wmsRawReturn.setAuditReason(auditReason);
        wmsRawReturn.setAuditBy(SecurityUtils.getUsername());
        wmsRawReturn.setAuditDate(new Date());
        return wmsRawReturnMapper.updateWmsRawReturn(wmsRawReturn);
    }

    /**
     * 原材料退库记录明细确认
     *
     * @param wmsRawReturnConfirmVo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int confirmWmsRawReturn(WmsRawReturnConfirmVo wmsRawReturnConfirmVo) {
        Long rawReturnId = wmsRawReturnConfirmVo.getRawReturnId();
        String materialBarcode = wmsRawReturnConfirmVo.getMaterialBarcode();
        BigDecimal returnAmount = wmsRawReturnConfirmVo.getReturnAmount();

        //todo: 判断质检状态,超出库位数量限制,超期判断
//        if (wmsRawReturnDetail.getQualityStatus() != null
//                && !wmsRawReturnDetail.getQualityStatus().equals(WmsConstants.RAW_RETURN_DETAIL_QUALITY_STATUS_PASS)) {
//            throw new ServiceException("质检通过才能出库");
//        }

        R<MesBaseBarcodeInfo> mesBaseBarcodeInfoR = remoteMesService.getBarcode(materialBarcode, SecurityConstants.INNER);
        if (mesBaseBarcodeInfoR == null) {
            throw new ServiceException("物料编码错误");
        }
        MesBaseBarcodeInfo mesBaseBarcodeInfo = mesBaseBarcodeInfoR.getData();
        if (mesBaseBarcodeInfo == null) {
            throw new ServiceException("物料编码错误");
        }
        WmsRawReturn wmsRawReturn = wmsRawReturnMapper.selectOnlyWmsRawReturnByRawReturnId(rawReturnId);
        if (!wmsRawReturn.getAuditStatus().equals(WmsConstants.WMS_AUDIT_STATUS_PASS)) {
            throw new ServiceException("审核未通过，不能出库");
        }

        // 判断本次退库数量+已退库数量是否大于计划退库数量
        BigDecimal planAmount = wmsRawReturn.getPlanAmount();
        BigDecimal hadReturnAmount = wmsRawReturn.getReturnAmount() == null ? BigDecimal.ZERO : wmsRawReturn.getReturnAmount();

        BigDecimal updatedReturnAmount = hadReturnAmount.add(returnAmount);
        if (updatedReturnAmount.compareTo(planAmount) > 0) {
            throw new ServiceException("退库数量不能大于" + planAmount);
        }


        String executeStatus = "";
        if (updatedReturnAmount.compareTo(planAmount) == 0) {
            executeStatus = WmsConstants.WMS_EXECUTE_STATUS_FINISH;
        } else {
            executeStatus = WmsConstants.WMS_EXECUTE_STATUS_EXECUTING;
        }

        Date currentDate = new Date();
        String userName = SecurityUtils.getUsername();
        //更新退库记录执行状态
        wmsRawReturn.setExecuteStatus(executeStatus);
        wmsRawReturn.setReturnAmount(updatedReturnAmount);
        wmsRawReturn.setUpdateDate(currentDate);
        wmsRawReturn.setUpdateBy(userName);
        wmsRawReturnMapper.updateWmsRawReturn(wmsRawReturn);

        //插入退库记录明细
        this.insertRawReturnDetails(wmsRawReturnConfirmVo, wmsRawReturn,
                mesBaseBarcodeInfo, userName, currentDate);

        //更新原材料库存
        this.updateRawStock(wmsRawReturnConfirmVo, mesBaseBarcodeInfo, userName, currentDate);

        //todo 同步erp
        return 1;
    }

    private void insertRawReturnDetails(WmsRawReturnConfirmVo wmsRawReturnConfirmVo, WmsRawReturn wmsRawReturn,
                                        MesBaseBarcodeInfo mesBaseBarcodeInfo, String userName, Date currentDate) {

        WmsRawReturnDetail wmsRawReturnDetail = new WmsRawReturnDetail();
        wmsRawReturnDetail.setRawReturnId(wmsRawReturn.getRawReturnId());
        wmsRawReturnDetail.setLocationCode(wmsRawReturnConfirmVo.getLocationCode());
        wmsRawReturnDetail.setMaterialBarcode(wmsRawReturnConfirmVo.getMaterialBarcode());
        wmsRawReturnDetail.setMaterialId(mesBaseBarcodeInfo.getMaterialId());
        wmsRawReturnDetail.setInstockBatch(mesBaseBarcodeInfo.getBatchCode());
        wmsRawReturnDetail.setPlanAmount(wmsRawReturnConfirmVo.getReturnAmount());
        wmsRawReturnDetail.setReturnAmount(wmsRawReturnConfirmVo.getReturnAmount());
        wmsRawReturnDetail.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_FINISH);
        wmsRawReturnDetail.setReturnPerson(userName);
        wmsRawReturnDetail.setReturnTime(currentDate);
        wmsRawReturnDetail.setReturnWay(WmsConstants.RAW_RETURN_RETURN_WAY_MANUAL);
        wmsRawReturnDetailMapper.insertWmsRawReturnDetail(wmsRawReturnDetail);

    }


    private void updateRawStock(WmsRawReturnConfirmVo wmsRawReturnConfirmVo, MesBaseBarcodeInfo mesBaseBarcodeInfo, String userName, Date currentDate) {
        String locationCode = wmsRawReturnConfirmVo.getLocationCode();
        String instockBatch = mesBaseBarcodeInfo.getBatchCode();

        WmsRawStock wmsRawStock = wmsRawStockMapper.selectRawStockByLocationAndBatch(locationCode, instockBatch);
        if (wmsRawStock == null) {
            throw new ServiceException("数据异常");
        } else {
            BigDecimal totalAmount = wmsRawStock.getTotalAmount() == null ? BigDecimal.ZERO : wmsRawStock.getTotalAmount();
            BigDecimal updatedTotalAmount = totalAmount.add(wmsRawReturnConfirmVo.getReturnAmount());
            wmsRawStock.setTotalAmount(updatedTotalAmount);
            wmsRawStock.setUpdateDate(currentDate);
            wmsRawStock.setUpdateBy(userName);
            wmsRawStockMapper.updateWmsRawStock(wmsRawStock);
        }
    }


    /**
     * 查询原材料退记录明细列表，供手持出库使用
     *
     * @param wmsRawReturnDetail 原材料退库记录明细
     * @return 原材料退库记录明细
     */
    @Override
    public List<WmsRawReturnDetail> selectAuditPassRawReturnDetails(WmsRawReturnDetail wmsRawReturnDetail) {
        return wmsRawReturnDetailMapper.selectAuditPassRawReturnDetails(wmsRawReturnDetail);
    }


    /**
     * 更新原材料退库记录的执行状态
     *
     * @param rawReturnId
     * @param rawReturnDetailId
     */
    private void updateRawReturnDetailExecuteStatus(Long rawReturnId, Long rawReturnDetailId) {
        WmsRawReturnDetail queryRawReturnDetail = new WmsRawReturnDetail();
        queryRawReturnDetail.setRawReturnId(rawReturnId);
        List<WmsRawReturnDetail> wmsRawReturnDetails = wmsRawReturnDetailMapper.selectWmsRawReturnDetailList(queryRawReturnDetail);

        boolean isExecuteFinish = true;
        for (WmsRawReturnDetail wmsRawReturnDetail : wmsRawReturnDetails) {
            if (!wmsRawReturnDetail.getRawReturnDetailId().equals(rawReturnDetailId)
                    && !wmsRawReturnDetail.getExecuteStatus().equals(WmsConstants.WMS_EXECUTE_STATUS_FINISH)) {
                isExecuteFinish = false;
            }
        }

        if (isExecuteFinish) {
            WmsRawReturn wmsRawReturn = wmsRawReturnMapper.selectWmsRawReturnByRawReturnId(rawReturnId);
            wmsRawReturn.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_FINISH);
            wmsRawReturnMapper.updateWmsRawReturn(wmsRawReturn);
        }
    }


    /**
     * 申请退库
     *
     * @param wmsRawReturn 原材料退库记录
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int applyRawReturn(WmsRawReturn wmsRawReturn) {
        List<WmsRawReturnDetail> rawReturnDetails = wmsRawReturn.getWmsRawReturnDetailList();
        //根据物料ID分组获取总申请数量
        Map<Long, BigDecimal> rawReturnDetailMap = rawReturnDetails.stream()
                .collect(Collectors.groupingBy(WmsRawReturnDetail::getMaterialId, HashMap::new, Collectors.reducing(BigDecimal.ZERO, WmsRawReturnDetail::getPlanAmount, BigDecimal::add)));

        String queryQualityStatus = WmsConstants.WMS_QUALITY_STATUS_PASS;
        List<WmsRawOutstockDetail> toUpdatedRawOutstockDetails = new ArrayList<>();
        Date currentDate = new Date();
        String userName = SecurityUtils.getUsername();
        for (Long materialId : rawReturnDetailMap.keySet()) {
            BigDecimal planAmount = rawReturnDetailMap.get(materialId);
            WmsRawReturn toUpdatedWmsRawReturn = new WmsRawReturn();
            toUpdatedWmsRawReturn.setWarehouseId(wmsRawReturn.getWarehouseId());
            toUpdatedWmsRawReturn.setPlanCode(wmsRawReturn.getPlanCode());
            toUpdatedWmsRawReturn.setPlanDetailCode(wmsRawReturn.getPlanDetailCode());
            toUpdatedWmsRawReturn.setTaskType(wmsRawReturn.getTaskType());
            toUpdatedWmsRawReturn.setTaskCode(Seq.getId());
//            toUpdatedWmsRawReturn.setProductId();
            toUpdatedWmsRawReturn.setApplyReason(wmsRawReturn.getApplyReason());

            toUpdatedWmsRawReturn.setMaterialId(materialId);
            toUpdatedWmsRawReturn.setPlanAmount(planAmount);
            //todo 审核状态默认为待审核，后续可根据系统参数判断保存是待审核还是直接审核通过
            toUpdatedWmsRawReturn.setApplyBy(userName);
            toUpdatedWmsRawReturn.setApplyDate(currentDate);
            toUpdatedWmsRawReturn.setAuditStatus(WmsConstants.RAW_OUTSTOCK_AUDIT_STATUS_TOAUDIT);
            toUpdatedWmsRawReturn.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE);

//            queryRawStock.setQualityStatus(queryQualityStatus);//todo：先不过滤质检状态
            int rows = wmsRawReturnMapper.insertWmsRawReturn(toUpdatedWmsRawReturn);
        }
        return 1;
    }

}
