package com.fjhx.service.logistics.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.base.BaseIdEntity;
import com.fjhx.constants.logistics.LogisticsConstant;
import com.fjhx.entity.apply.ApplyPurchase;
import com.fjhx.entity.logistics.LogisticsDetails;
import com.fjhx.entity.logistics.LogisticsInfo;
import com.fjhx.entity.product.ProductInfo;
import com.fjhx.entity.purchase.Purchase;
import com.fjhx.entity.quality.QualityDetails;
import com.fjhx.entity.quality.QualityInfo;
import com.fjhx.entity.stock.StockJournal;
import com.fjhx.enums.purchase.PurchaseStatusEnum;
import com.fjhx.enums.stock.InTypeEnum;
import com.fjhx.mapper.logistics.LogisticsInfoMapper;
import com.fjhx.params.logistics.DeliverDetailsVo;
import com.fjhx.params.logistics.LogisticsInfoVo;
import com.fjhx.params.stock.InStockAdd;
import com.fjhx.params.stock.StockChangeVo;
import com.fjhx.service.apply.ApplyPurchaseService;
import com.fjhx.service.logistics.LogisticsDetailsService;
import com.fjhx.service.logistics.LogisticsInfoService;
import com.fjhx.service.product.ProductInfoService;
import com.fjhx.service.purchase.PurchaseService;
import com.fjhx.service.quality.QualityDetailsService;
import com.fjhx.service.quality.QualityInfoService;
import com.fjhx.service.stock.StockService;
import com.fjhx.uitl.code.CodeEnum;
import com.fjhx.uitl.kd100.KD100Util;
import com.fjhx.utils.Assert;
import com.fjhx.utils.FileClientUtil;
import com.fjhx.utils.UserClientUtil;
import com.fjhx.utils.wrapperUtil.IWrapper;
import com.fjhx.utils.wrapperUtil.KeywordData;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tool.utils.Func;
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;

/**
 * <p>
 * 物流信息 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-11-30
 */
@Service
public class LogisticsInfoServiceImpl extends ServiceImpl<LogisticsInfoMapper, LogisticsInfo> implements LogisticsInfoService {

    @Autowired
    private LogisticsDetailsService logisticsDetailsService;

    @Autowired
    private ApplyPurchaseService applyPurchaseService;

    @Autowired
    private ProductInfoService productInfoService;

    @Autowired
    private PurchaseService purchaseService;

    @Autowired
    private StockService stockService;

    @Autowired
    private QualityInfoService qualityInfoService;

    @Autowired
    private QualityDetailsService qualityDetailsService;

    @Override
    public Page<LogisticsInfo> getPage(Map<String, Object> condition) {

        IWrapper<LogisticsInfo> wrapper = IWrapper.getWrapper(condition);

        return page(condition, wrapper);
    }

    /**
     * 采购入库列表
     *
     * @param condition 查询条件
     * @return
     */
    @Override
    public Page<LogisticsInfo> getPurchaseInStockPage(Map<String, Object> condition) {

        IWrapper<LogisticsInfo> wrapper = IWrapper.getWrapper(condition);
        wrapper.eq("t1", LogisticsInfo::getStatus, LogisticsConstant.Status.STATUS_1)
                .lt("t1", LogisticsInfo::getInStockStatus, LogisticsConstant.InStockStatus.STATUS_30)
                .eq("t1", LogisticsInfo::getBusinessType, 1)
                .between("t2", Purchase::getStatus, PurchaseStatusEnum.STATUS_30.getKey(), PurchaseStatusEnum.STATUS_40.getKey())
                .eq("t1", LogisticsInfo::getInStockStatus)
                .keyword(new KeywordData("t1.`code`"),
                        new KeywordData("t2.`code`"),
                        new KeywordData("t3.`name`"))
                .orderByDesc("t1", ApplyPurchase::getId);

        Page<LogisticsInfo> page = baseMapper.getPurchaseInStockPage(createPage(condition), wrapper);
        if (Func.isNotEmpty(page.getRecords())) {
            Map<Long, String> userNameMap = UserClientUtil.getUserNameMap(page.getRecords(), LogisticsInfo::getCreateUser);
            for (LogisticsInfo entity : page.getRecords()) {
                if (Func.isNotEmpty(userNameMap) && Func.isNotEmpty(userNameMap.get(entity.getCreateUser()))) {
                    entity.setPurchaseName(userNameMap.get(entity.getCreateUser()));
                }
            }
        }

        return page;
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void add(LogisticsInfoVo logisticsInfoVo) {
        if (Func.isAnyBlank(logisticsInfoVo.getLogisticsCompanyCode(), logisticsInfoVo.getCode())) {
            throw new ServiceException("物流信息不能为空");
        }

        List<LogisticsDetails> details = logisticsInfoVo.getDetails();
        Assert.notEmpty(details, "发货明细不能为空");

        // 获取已发货数量map<申购单id, 已发货数量>
        Map<Long, BigDecimal> deliverQuantityMap = logisticsDetailsService.getDeliverQuantityMap(logisticsInfoVo.getBusinessId());
        // 获取申购数量
        Map<Long, BigDecimal> applyPurchaseQuantityMap = applyPurchaseService.list(ApplyPurchase::getPurchaseId, logisticsInfoVo.getBusinessId())
                .stream().collect(Collectors.toMap(BaseIdEntity::getId, ApplyPurchase::getQuantity, BigDecimal::add));

        details = details.stream()
                .filter(item ->
                        ObjectUtil.isNotEmpty(item.getShipmentQuantity()) && item.getShipmentQuantity().compareTo(BigDecimal.ZERO) > 0
                ).peek(item -> {
                    Long applyPurchaseId = item.getApplyPurchaseId();
                    Assert.notEmpty(applyPurchaseId, "申购id不能为空");

                    // 获取已发货数量
                    BigDecimal deliverQuantity = ObjectUtil.defaultIfNull(deliverQuantityMap.get(applyPurchaseId), BigDecimal.ZERO);
                    // 获取申购数量
                    BigDecimal applyQuantity = ObjectUtil.defaultIfNull(applyPurchaseQuantityMap.get(applyPurchaseId), BigDecimal.ZERO);

                    // 判断申购数量是否大于发货数量
                    if (deliverQuantity.add(item.getShipmentQuantity()).compareTo(applyQuantity) > 0) {
                        throw new ServiceException("发货总数量不能大于发货数量");
                    }

                })
                .collect(Collectors.toList());
        Assert.notEmpty(details, "发货数量不能全为0");


        Integer state = -1;
        // 查询快递100的物流信息
        try {
            JSONObject result = KD100Util.queryTrack(logisticsInfoVo.getLogisticsCompanyCode(), logisticsInfoVo.getCode());
            state = result.getInteger("state");
        } catch (Exception e) {
            log.error("未找到快递消息", e);
        }

        if (!Objects.equals(state, LogisticsConstant.KD100Status.STATUS_3)) {
            // 如果不是已签收状态，则开启订阅（物流状态跟踪并推送）
            KD100Util.subscribe(logisticsInfoVo.getLogisticsCompanyCode(), logisticsInfoVo.getCode(), new Date());
        }

        logisticsInfoVo.setLogisticsStatus(state);
        logisticsInfoVo.setStatus(LogisticsConstant.Status.STATUS_0);
        logisticsInfoVo.setInStockStatus(LogisticsConstant.InStockStatus.STATUS_10);
        save(logisticsInfoVo);

        details.forEach(o -> {
            o.setLogisticsInfoId(logisticsInfoVo.getId());
            o.setLogisticsInfoCode(logisticsInfoVo.getCode());
            o.setReceiptQuantity(BigDecimal.ZERO);
        });

        //保存附件
        FileClientUtil.bindingFile(logisticsInfoVo.getId(), logisticsInfoVo.getFileInfos());

        logisticsDetailsService.saveBatch(details);
    }

    @Override
    public void edit(LogisticsInfoVo logisticsInfoVo) {
        updateById(logisticsInfoVo);
    }

    @Override
    public void delete(LogisticsInfoVo logisticsInfoVo) {
        removeById(logisticsInfoVo.getId());
    }

    /**
     * 根据采购ID查询
     *
     * @param purchaseIds 采购ID集合
     * @return
     */
    @Override
    public List<LogisticsInfo> getByPurchaseIds(List<Long> purchaseIds) {
        if (Func.isEmpty(purchaseIds)) {
            return new ArrayList<>();
        }
        return lambdaQuery().in(LogisticsInfo::getBusinessId, purchaseIds).list();
    }

    /**
     * 根据采购ID查询
     *
     * @param purchaseIds 采购ID集合
     * @return
     */
    @Override
    public Map<Long, List<LogisticsInfo>> getByPurchaseIdsToMap(List<Long> purchaseIds) {
        List<LogisticsInfo> list = getByPurchaseIds(purchaseIds);
        if (Func.isEmpty(list)) {
            return new HashMap<>();
        }
        return list.stream().collect(Collectors.groupingBy(LogisticsInfo::getBusinessId));
    }

    /**
     * 根据物流单号跟新物流状态
     *
     * @param code  物流单号
     * @param state 物流状态
     */
    @Override
    public void updateStatusByCode(String code, Integer state) {
        lambdaUpdate().set(LogisticsInfo::getStatus, state).eq(LogisticsInfo::getCode, code).update();
    }

    /**
     * 根据业务ID查询物流单号
     *
     * @param businessId 业务ID
     * @return
     */
    @Override
    public List<LogisticsInfo> codeSelectByBusinessId(Long businessId) {
        return lambdaQuery()
                .select(LogisticsInfo::getId, LogisticsInfo::getCode)
                .eq(LogisticsInfo::getBusinessType, 1)
                .eq(LogisticsInfo::getBusinessId, businessId)
                .eq(LogisticsInfo::getStatus, LogisticsConstant.Status.STATUS_0)
                .list();
    }

    @Override
    public List<DeliverDetailsVo> deliverDetails(Long id) {

        // 获取采购的产品
        List<ApplyPurchase> applyPurchaseList = applyPurchaseService.list(q -> q.eq(ApplyPurchase::getPurchaseId, id));
        if (applyPurchaseList.size() == 0) {
            return new ArrayList<>();
        }

        // 产品id列表
        List<Long> productIdList = applyPurchaseList.stream().map(ApplyPurchase::getGoodsId).collect(Collectors.toList());
        // 采购map
        Map<Long, ProductInfo> productMap = productInfoService.getKEntity(BaseIdEntity::getId, q -> q.in(BaseIdEntity::getId, productIdList));

        // 获取已发货数量
        Map<Long, BigDecimal> deliverQuantityMap = logisticsDetailsService.getDeliverQuantityMap(id);

        return applyPurchaseList.stream().map(item -> {
            DeliverDetailsVo deliverDetailsVo = new DeliverDetailsVo();

            // 赋值申购信息
            deliverDetailsVo.setProductId(item.getGoodsId());
            deliverDetailsVo.setPurchaseId(item.getPurchaseId());
            deliverDetailsVo.setApplyPurchaseId(item.getId());
            deliverDetailsVo.setPurchaseQuantity(item.getQuantity());

            // 赋值产品信息
            ProductInfo productInfo = productMap.get(item.getGoodsId());
            if (productInfo != null) {
                deliverDetailsVo.setProductName(productInfo.getName());
                deliverDetailsVo.setProductCode(productInfo.getCode());
            }

            // 赋值已发货数量
            deliverDetailsVo.setDeliverQuantity(ObjectUtil.defaultIfNull(deliverQuantityMap.get(item.getId()), BigDecimal.ZERO));
            return deliverDetailsVo;

        }).collect(Collectors.toList());
    }

    @Override
    public void arrivalNotice(LogisticsInfoVo entity) {

        // 采购id
        Long purchaseId = entity.getPurchaseId();
        Assert.notEmpty(purchaseId, "采购id不能为空");

        entity.setStatus(LogisticsConstant.Status.STATUS_1);
        updateById(entity);

        // // 获取已发货数量
        // Map<Long, BigDecimal> deliverQuantityMap = logisticsDetailsService.getDeliverQuantityMap(purchaseId);
        //
        // List<ApplyPurchase> list = applyPurchaseService.list(q -> q.eq(ApplyPurchase::getPurchaseId, purchaseId));
        // for (ApplyPurchase applyPurchase : list) {
        //     Long id = applyPurchase.getId();
        //
        //     // 获取已申购数量
        //     BigDecimal bigDecimal = deliverQuantityMap.get(id);
        //
        // }

        // TODO 判断部分到货还是全部到货
        Purchase purchase = new Purchase();
        purchase.setId(purchaseId);
        purchase.setStatus(PurchaseStatusEnum.STATUS_40.getKey());
        purchaseService.updateById(purchase);


    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void inStock(InStockAdd inStockAdd) {
        List<InStockAdd.InStockAddDetails> list = inStockAdd.getList();
        Long logisticsInfoId = inStockAdd.getLogisticsInfoId();

        StockChangeVo stockChangeVo = new StockChangeVo();
        stockChangeVo.setTypeEnum(InTypeEnum.PURCHASE);
        stockChangeVo.setChangeDetailsList(list);
        List<StockJournal> stockJournals = stockService.changeQuantity(stockChangeVo);

        // 修改入库数量
        Map<Long, BigDecimal> collect = list.stream().collect(Collectors.toMap(
                InStockAdd.InStockAddDetails::getBusinessId,
                InStockAdd.InStockAddDetails::getChangeQuantity
        ));

        List<LogisticsDetails> logisticsDetails = logisticsDetailsService.list(
                q -> q.eq(LogisticsDetails::getLogisticsInfoId, logisticsInfoId));

        // 本次采购入库是否完成
        boolean completeFlag = true;

        for (LogisticsDetails logisticsDetail : logisticsDetails) {

            // 发货数量
            BigDecimal shipmentQuantity = logisticsDetail.getShipmentQuantity();

            // 入库数量
            BigDecimal receiptQuantity = logisticsDetail.getReceiptQuantity();

            // 本次入库数量
            BigDecimal bigDecimal = ObjectUtil.defaultIfNull(collect.get(logisticsDetail.getId()), BigDecimal.ZERO);

            int compareTo = receiptQuantity.add(bigDecimal).compareTo(shipmentQuantity);
            if (compareTo > 0) {
                throw new ServiceException("入库数量不能超过发货数量");
            } else if (compareTo < 0) {
                completeFlag = false;
            }

            // 添加发货数量
            logisticsDetail.setReceiptQuantity(receiptQuantity.add(bigDecimal));
        }
        logisticsDetailsService.updateBatchById(logisticsDetails);

        // 修改入库状态
        LogisticsInfo logisticsInfo = getById(logisticsInfoId);
        Integer inStockStatus = completeFlag ? LogisticsConstant.InStockStatus.STATUS_30 : LogisticsConstant.InStockStatus.STATUS_20;
        if (!inStockStatus.equals(logisticsInfo.getInStockStatus())) {
            logisticsInfo.setInStockStatus(inStockStatus);
            updateById(logisticsInfo);
        }

        // 添加质检
        QualityInfo qualityInfo = new QualityInfo();
        qualityInfo.setCode(CodeEnum.QUALITY.getCode());
        qualityInfo.setLogisticsInfoId(logisticsInfoId);
        qualityInfo.setLogisticsInfoCode(logisticsInfo.getCode());
        qualityInfo.setStatus(1);
        qualityInfo.setResultType(1);
        qualityInfoService.save(qualityInfo);

        // 添加质检明细
        List<QualityDetails> qualityDetailsList = stockJournals.stream().map(item -> {
            QualityDetails qualityDetails = new QualityDetails();
            qualityDetails.setQualityInfoId(qualityInfo.getId());
            qualityDetails.setStockJournalId(item.getId());
            qualityDetails.setLogisticsDetailsId(item.getBusinessId());
            qualityDetails.setProductInfoId(item.getGoodsId());
            qualityDetails.setWarehouseId(item.getWarehouseId());
            qualityDetails.setTotalQuantity(item.getChangeQuantity());
            qualityDetails.setQualifiedQuantity(BigDecimal.ZERO);
            qualityDetails.setDisqualificationQuantity(BigDecimal.ZERO);
            return qualityDetails;
        }).collect(Collectors.toList());
        qualityDetailsService.saveBatch(qualityDetailsList);
    }

}
