package com.gree.mall.manager.logic.goods;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gree.mall.manager.bean.admin.AdminUserCom;
import com.gree.mall.manager.bean.goods.*;
import com.gree.mall.manager.commonmapper.CommonMapper;
import com.gree.mall.manager.enums.CodeAccStatusEnum;
import com.gree.mall.manager.enums.CodeAccTypeEnum;
import com.gree.mall.manager.enums.ExamineStatusEnum;
import com.gree.mall.manager.enums.IsYesNoEnum;
import com.gree.mall.manager.enums.admin.AdminWebsitTypeEnum;
import com.gree.mall.manager.enums.base.BaseEnum;
import com.gree.mall.manager.enums.material.GoodsMaterialTypeEnum;
import com.gree.mall.manager.exception.RemoteServiceException;
import com.gree.mall.manager.logic.common.CommonLogic;
import com.gree.mall.manager.plus.entity.*;
import com.gree.mall.manager.plus.service.*;
import com.gree.mall.manager.utils.StringUtil;
import com.gree.mall.manager.utils.excel.ExcelUtils;
import com.gree.mall.manager.zfire.bean.ZfireParamBean;
import com.gree.mall.manager.zfire.util.FieldUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@Service
public class GoodsPurchaseLogic {

    private final CommonLogic commonLogic;
    private final CommonMapper commonMapper;
    private final GoodsPurchaseService goodsPurchaseService;
    private final GoodsPurchaseItemService goodsPurchaseItemService;
    private final GoodsPurchaseCodeService goodsPurchaseCodeService;
    private final GoodsMaterialService goodsMaterialService;
    private final GoodsMaterialItemService goodsMaterialItemService;
    private final GoodsCodeAccService goodsCodeAccService;
    private final AdminWebsitService adminWebsitService;
    private final JxGoodsLogic jxGoodsLogic;
    private final GoodsMaterialStorageService goodsMaterialStorageService;
    private final StorageService storageService;

    public IPage<GoodsPurchaseVO> page(ZfireParamBean zfireParamBean) {
        FieldUtils.supplyParam(zfireParamBean, GoodsPurchaseVO.class, commonLogic.getAdminUser());
        IPage<GoodsPurchaseVO> page = commonMapper.goodsPurchaseList(new Page(zfireParamBean.getPageNum(), zfireParamBean.getPageSize()), zfireParamBean);

        return page;
    }

    public IPage<GoodsPurchaseItemVO> itemPage(ZfireParamBean zfireParamBean) {
        FieldUtils.supplyParam(zfireParamBean, GoodsPurchaseItemVO.class, commonLogic.getAdminUser());
        IPage<GoodsPurchaseItemVO> page = commonMapper.goodsPurchaseItemList(new Page(zfireParamBean.getPageNum(), zfireParamBean.getPageSize()), zfireParamBean);

        return page;
    }

    public IPage<GoodsPurchaseCodeVO> codePage(ZfireParamBean zfireParamBean) {
        FieldUtils.supplyParam(zfireParamBean, GoodsPurchaseCodeVO.class, commonLogic.getAdminUser());
        IPage<GoodsPurchaseCodeVO> page = commonMapper.goodsPurchaseCodeList(new Page(zfireParamBean.getPageNum(), zfireParamBean.getPageSize()), zfireParamBean);

        return page;
    }

    public GoodsPurchaseBean detail(String id, Boolean isQuery) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        String companyId = null;
        if (Objects.nonNull(adminUser.getAdminCompanyWechat())) {
            companyId = adminUser.getAdminCompanyWechat().getCompanyWechatId();
        }
        GoodsPurchaseBean bean = new GoodsPurchaseBean();
        GoodsPurchase purchase = goodsPurchaseService.lambdaQuery()
                .eq(StringUtils.isNotBlank(companyId), GoodsPurchase::getCompanyWechatId, companyId)
                .eq(GoodsPurchase::getId, id)
                .one();

        if (Objects.nonNull(purchase)) {
            List<GoodsPurchaseItem> items = goodsPurchaseItemService.lambdaQuery()
                    .eq(GoodsPurchaseItem::getGoodsPurchaseId, purchase.getId())
                    .list();
            List<GoodsPurchaseItemBean> itemBeans = BeanUtil.copyToList(items, GoodsPurchaseItemBean.class);

            if (Objects.nonNull(isQuery) && isQuery) {


                List<GoodsMaterialStorage> goodsMaterialStorages = goodsMaterialStorageService.lambdaQuery()
                        .in(GoodsMaterialStorage::getGoodsMaterialId, items.stream()
                                .map(GoodsPurchaseItem::getGoodsMaterialId)
                                .collect(Collectors.toList()))
                        .list();


                for (GoodsPurchaseItemBean itemBean : itemBeans) {
                    Integer stockQty = goodsMaterialStorages.stream().map(GoodsMaterialStorage::getStockQty).reduce(Integer::sum).orElse(0);
                    if (Objects.nonNull(stockQty)) {
                        itemBean.setStockQty(stockQty);
                    }
                }
            }
            bean.setItems(itemBeans);

            BeanUtils.copyProperties(purchase, bean);
        }

        return bean;
    }

    @Transactional(rollbackFor = Exception.class)
    public GoodsPurchaseBean add(GoodsPurchaseBean bean) {
        AdminUserCom adminUser = commonLogic.getAdminUser();

        if (StringUtil.isEmpty(bean.getStorageId())){
            Storage storage = storageService.lambdaQuery().eq(Storage::getCompanyWechatId, adminUser.getCompanyWechatId())
                    .eq(Storage::getIsDefault, true)
                    .like(Storage::getType, "商品")
                    .last("limit 1").one();

            if(storage == null)
                throw new RemoteServiceException("未初始化配置");

            bean.setStorageId(storage.getStorageId());
            bean.setStorageName(storage.getStorageName());

        }

        if (Objects.nonNull(adminUser.getAdminCompanyWechat())) {
            bean.setCompanyWechatId(adminUser.getAdminCompanyWechat().getCompanyWechatId());
            bean.setCompanyWechatName(adminUser.getAdminCompanyWechat().getCompanyName());
        }

        AdminWebsit adminWebsit = adminWebsitService.lambdaQuery()
                .eq(AdminWebsit::getCompanyWechatId,adminUser.getCompanyWechatId())
                .eq(AdminWebsit::getType, AdminWebsitTypeEnum.B.getKey())
                .last("limit 1")
                .one();

        if (Objects.isNull(adminWebsit)) {
            throw new RemoteServiceException("未能找到当前账号归属商户信息");
        }

        if (StringUtils.isBlank(bean.getVenderId())) {
            throw new RemoteServiceException("请选择供应商");
        }

        if (CollectionUtil.isEmpty(bean.getItems())) {
            throw new RemoteServiceException("商品信息不能为空");
        }

        bean.setId(IdWorker.getIdStr())
                .setJoinCode(adminWebsit.getJoinCode())
                .setStatus(ExamineStatusEnum.SAVE.getKey());

        // 检查商品信息唯一
        checkItemUnique(bean);

        List<GoodsPurchaseItem> items = this.handleItemMethod(bean.getItems(), bean.getId(), true);


        goodsPurchaseItemService.saveBatch(items);

        Integer totalQty = items.stream().mapToInt(GoodsPurchaseItem::getQty).sum();
        double totalAmount = items.stream().mapToDouble(v -> v.getAmount().doubleValue()).sum();

        bean.setTotalQty(totalQty)
                .setTotalAmount(BigDecimal.valueOf(totalAmount))
                .insert();

        return bean;
    }

    private List<GoodsPurchaseItem> handleItemMethod(List<GoodsPurchaseItemBean> itemBeans, String purchaseId, boolean initImportQty) {
        List<GoodsPurchaseItem> items = new ArrayList<>();
        // 商品信息
        List<GoodsMaterial> goodsMaterials = goodsMaterialService.lambdaQuery()
                .in(GoodsMaterial::getId, itemBeans.stream()
                        .map(GoodsPurchaseItem::getGoodsMaterialId)
                        .filter(StringUtils::isNotBlank)
                        .collect(Collectors.toList()))
                .list();

        Map<String, GoodsMaterial> materialMap = goodsMaterials.stream()
                .collect(Collectors.toMap(GoodsMaterial::getId, Function.identity()));

        // 商品子物料信息
        List<GoodsMaterialItem> goodsMaterialItems = goodsMaterialItemService.lambdaQuery()
                .in(GoodsMaterialItem::getGoodsMaterialId, materialMap.keySet())
                .list();

        Map<String, List<GoodsMaterialItem>> materialItemMap = goodsMaterialItems.stream()
                .collect(Collectors.groupingBy(GoodsMaterialItem::getGoodsMaterialId));

        for (GoodsPurchaseItemBean itemBean : itemBeans) {
            if (StringUtils.isBlank(itemBean.getGoodsMaterialId())) {
                throw new RemoteServiceException("第" + itemBean.getIndex() + "行, 请选商品");
            }
            if (Objects.isNull(itemBean.getQty()) || itemBean.getQty() <= 0) {
                throw new RemoteServiceException("第" + itemBean.getIndex() + "行, 请填写有效数量");
            }

            if (Objects.isNull(itemBean.getPrice()) || itemBean.getPrice().compareTo(BigDecimal.ZERO) < 0) {
                throw new RemoteServiceException("第" + itemBean.getIndex() + "行, 请填写有效采购价格");
            }

            GoodsMaterial goodsMaterial = materialMap.get(itemBean.getGoodsMaterialId());
            if (Objects.isNull(goodsMaterial)) {
                throw new RemoteServiceException("第" + itemBean.getIndex() + "行, 商品信息不存在");
            }

            List<GoodsMaterialItem> materialItems = materialItemMap.get(goodsMaterial.getId());

            int innerQty = 0;
            int outQty = 0;
            int partsQty = 0;

            for (GoodsMaterialItem materialItem : materialItems) {
                if (materialItem.getType().equals(GoodsMaterialTypeEnum.INSIDE.getKey())) {
                    innerQty = innerQty + materialItem.getQty() * itemBean.getQty();
                } else if (materialItem.getType().equals(GoodsMaterialTypeEnum.OUT.getKey())) {
                    outQty = outQty + materialItem.getQty() * itemBean.getQty();
                } else {
                    partsQty = partsQty + materialItem.getQty() * itemBean.getQty();
                }
            }

            itemBean.setGoodsPurchaseId(purchaseId)
                    .setBrandId(goodsMaterial.getBrandId())
                    .setBrandName(goodsMaterial.getBrandName())
                    .setMainId(goodsMaterial.getMainId())
                    .setMainName(goodsMaterial.getMainName())
                    .setSmallId(goodsMaterial.getSmallId())
                    .setSmallName(goodsMaterial.getSmallName())
                    .setGoodsMaterialName(goodsMaterial.getGoodsName())
                    .setSeriesName(goodsMaterial.getSeriesName())
                    .setSpecsName(goodsMaterial.getSpecsName())
                    .setUnit(goodsMaterial.getUnit())
                    .setInsideQty(innerQty)
                    .setOutQty(outQty)
                    .setPartsQty(partsQty)
                    .setAmount(itemBean.getPrice().multiply(BigDecimal.valueOf(itemBean.getQty())));

            if (initImportQty) {
                itemBean.setInsideCodeQty(0)
                        .setOutCodeQty(0)
                        .setPartsCodeQty(0);
            }

            items.add(itemBean);
        }
        return items;
    }

    @Transactional(rollbackFor = Exception.class)
    public void update(GoodsPurchaseBean bean, AdminUserCom adminUser) {
        if (Objects.nonNull(adminUser.getAdminCompanyWechat())) {
            bean.setCompanyWechatId(adminUser.getAdminCompanyWechat().getCompanyWechatId());
            bean.setCompanyWechatName(adminUser.getAdminCompanyWechat().getCompanyName());
        }

        GoodsPurchase oldPurchase = goodsPurchaseService.lambdaQuery()
                .eq(GoodsPurchase::getCompanyWechatId, bean.getCompanyWechatId())
                .eq(GoodsPurchase::getId, bean.getId())
                .one();

        if (Objects.isNull(oldPurchase)) {
            throw new RemoteServiceException("商品采购入库单不存在");
        }

        if (CollectionUtil.isEmpty(bean.getItems())) {
            throw new RemoteServiceException("商品信息不能为空");
        }

        // 检查商品信息唯一
        checkItemUnique(bean);

        // 处理商品明细
        List<GoodsPurchaseItem> handleAfterItems = new ArrayList<>();

        List<GoodsPurchaseItem> goodsPurchaseItemList = goodsPurchaseItemService.lambdaQuery()
                .eq(GoodsPurchaseItem::getGoodsPurchaseId, bean.getId())
                .list();

        Map<String, GoodsPurchaseItem> oldPurchaseItemMap = goodsPurchaseItemList.stream()
                .collect(Collectors.toMap(GoodsPurchaseItem::getGoodsMaterialId, Function.identity()));

        // 过滤出旧明细记录已删除记录
        List<String> beanItemList = bean.getItems().stream().map(GoodsPurchaseItemBean::getId)
                .filter(StringUtils::isNotBlank)
                .collect(Collectors.toList());
        for (GoodsPurchaseItem purchaseItem : goodsPurchaseItemList) {
            List<String> itemIdList = new ArrayList<>();
            if (!beanItemList.contains(purchaseItem.getId())) {
                itemIdList.add(purchaseItem.getId());
            }
            goodsPurchaseItemService.lambdaUpdate()
                    .in(GoodsPurchaseItem::getId, itemIdList)
                    .remove();
            goodsPurchaseCodeService.lambdaUpdate()
                    .in(GoodsPurchaseCode::getGoodsPurchaseItemId, itemIdList)
                    .remove();
        }


        // 过滤出明细id不为空并且商品编号不一致的商品, 清空已变更商品子物料条码
        List<GoodsPurchaseItemBean> changeItemList = bean.getItems().stream()
                .filter(v -> StringUtils.isNotBlank(v.getId()) && !oldPurchaseItemMap.containsKey(v.getGoodsMaterialId()))
                .collect(Collectors.toList());

        if (CollectionUtil.isNotEmpty(changeItemList)) {
            // 按商品明细id清空已变更商品子物料条码
            goodsPurchaseCodeService.lambdaUpdate()
                    .eq(GoodsPurchaseCode::getGoodsPurchaseItemId, changeItemList.stream()
                            .map(GoodsPurchaseItemBean::getId)
                            .collect(Collectors.toList()))
                    .remove();

            // 重新设置商品明细内容
            handleAfterItems.addAll(this.handleItemMethod(changeItemList, oldPurchase.getId(), true));
        }

        // 过滤出明细id不为空并且商品编号一致的商品
        List<GoodsPurchaseItemBean> updateItemList = bean.getItems().stream()
                .filter(v -> StringUtils.isNotBlank(v.getId()) && oldPurchaseItemMap.containsKey(v.getGoodsMaterialId()))
                .collect(Collectors.toList());

        if (CollectionUtil.isNotEmpty(updateItemList)) {
            // 重新设置商品明细内容
            handleAfterItems.addAll(this.handleItemMethod(changeItemList, oldPurchase.getId(), false));
        }

        // 过滤出新增的商品
        List<GoodsPurchaseItemBean> addItemList = bean.getItems().stream()
                .filter(v -> StringUtils.isBlank(v.getId()))
                .collect(Collectors.toList());

        if (CollectionUtil.isNotEmpty(addItemList)) {
            // 添加商品明细内容
            handleAfterItems.addAll(this.handleItemMethod(changeItemList, oldPurchase.getId(), true));
        }

        goodsPurchaseItemService.saveOrUpdateBatch(handleAfterItems);

        Integer totalQty = handleAfterItems.stream().mapToInt(GoodsPurchaseItem::getQty).sum();
        double totalAmount = handleAfterItems.stream().mapToDouble(v -> v.getAmount().doubleValue()).sum();

        oldPurchase.setTotalQty(totalQty)
                .setTotalAmount(BigDecimal.valueOf(totalAmount))
                .setVenderId(oldPurchase.getVenderId())
                .setVenderName(oldPurchase.getVenderName())
                .setFileUrl(oldPurchase.getFileUrl())
                .setRemark(oldPurchase.getRemark())
                .updateById();
    }

    private void checkItemUnique(GoodsPurchaseBean bean) {
        Map<String, List<GoodsPurchaseItemBean>> materialGroup = bean.getItems().stream()
                .collect(Collectors.groupingBy(GoodsPurchaseItemBean::getGoodsMaterialId));

        for (Map.Entry<String, List<GoodsPurchaseItemBean>> entry : materialGroup.entrySet()) {
            if (entry.getValue().size() > 1) {
                throw new RemoteServiceException("发现重复的商品, 请检查!");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void submit(String id) throws InterruptedException {
        this.commonHandlePurchase(id, ExamineStatusEnum.WAIT);


    }

    private void commonHandlePurchase(String id, ExamineStatusEnum statusEnum) throws InterruptedException {
        AdminUserCom adminUser = commonLogic.getAdminUser();

        String companyId = null;
        if (Objects.nonNull(adminUser.getAdminCompanyWechat())) {
            companyId = adminUser.getAdminCompanyWechat().getCompanyWechatId();
        }
        GoodsPurchase purchase = goodsPurchaseService.lambdaQuery()
                .eq(GoodsPurchase::getId, id)
                .eq(GoodsPurchase::getCompanyWechatId, companyId)
                .one();

        if (Objects.isNull(purchase)) {
            throw new RemoteServiceException("单据不存在, 提交失败");
        }

        if (statusEnum.getKey().equals(ExamineStatusEnum.WAIT.getKey())
                && !purchase.getStatus().equals(ExamineStatusEnum.SAVE.getKey())) {
            throw new RemoteServiceException("当前单据: \"" +
                    BaseEnum.keyToEnumNotNull(ExamineStatusEnum.class, purchase.getStatus()).getRemark() + "\"状态, 提交失败");
        }

        if (!statusEnum.getKey().equals(ExamineStatusEnum.WAIT.getKey())
                && !purchase.getStatus().equals(ExamineStatusEnum.WAIT.getKey())) {
            throw new RemoteServiceException("当前单据: \"" +
                    BaseEnum.keyToEnumNotNull(ExamineStatusEnum.class, purchase.getStatus()).getRemark() + "\"状态, 审核失败");
        }

        // 检查商品子物料的条码数量是否对应
        List<GoodsPurchaseItem> purchaseItemList = goodsPurchaseItemService.lambdaQuery()
                .eq(GoodsPurchaseItem::getGoodsPurchaseId, id)
                .list();

        // 查出入库单所有条码
        List<GoodsPurchaseCode> purchaseCodeList = goodsPurchaseCodeService.lambdaQuery()
                .eq(GoodsPurchaseCode::getGoodsPurchaseId, id)
                .list();

        Map<String, List<GoodsPurchaseCode>> codeGroupMap = purchaseCodeList.stream()
                .collect(Collectors.groupingBy(v -> v.getGoodsPurchaseItemId() + "-" + v.getGoodsMaterialItemId()));

        // 查出子物料信息
        List<GoodsMaterialItem> materialItemList = goodsMaterialItemService.lambdaQuery()
                .in(GoodsMaterialItem::getGoodsMaterialId, purchaseItemList.stream()
                        .map(GoodsPurchaseItem::getGoodsMaterialId)
                        .collect(Collectors.toList()))
                .list();

        Map<String, List<GoodsMaterialItem>> materialItemGroupMap = materialItemList.stream()
                .collect(Collectors.groupingBy(GoodsMaterialItem::getGoodsMaterialId));

        for (GoodsPurchaseItem item : purchaseItemList) {
            // 关联条码时检查商品子物料的条码数量
            if (purchase.getJoinCode().equals("CODE")) {
                // 检查条码数量
                this.checkCodeQty(item, materialItemGroupMap, codeGroupMap);
            }
            if (ExamineStatusEnum.WAIT.getKey().equals(statusEnum.getKey())) {
                item.setOrigQty(item.getQty());
            }
        }

        if (ExamineStatusEnum.WAIT.getKey().equals(statusEnum.getKey())) {
            for (GoodsPurchaseCode code : purchaseCodeList) {
                code.setOrigCodeQty(code.getCodeQty());
            }
            goodsPurchaseItemService.saveOrUpdateBatch(purchaseItemList);
            if (purchase.getJoinCode().equals("CODE")) {
                goodsPurchaseCodeService.saveOrUpdateBatch(purchaseCodeList);
            }
        }

        // 更新商品采购入库单状态
        goodsPurchaseService.lambdaUpdate()
                .set(GoodsPurchase::getStatus, statusEnum.getKey().equals(ExamineStatusEnum.FAIL.getKey()) ? ExamineStatusEnum.SAVE.getKey() : statusEnum.getKey())
                .set(statusEnum.getKey().equals(ExamineStatusEnum.WAIT.getKey()), GoodsPurchase::getSubmitBy, adminUser.getNickName())
                .set(statusEnum.getKey().equals(ExamineStatusEnum.WAIT.getKey()), GoodsPurchase::getSubmitTime, DateUtil.date())
                .set(statusEnum.getKey().equals(ExamineStatusEnum.OK.getKey())
                        || statusEnum.getKey().equals(ExamineStatusEnum.FAIL.getKey()),
                        GoodsPurchase::getExamineBy, adminUser.getNickName())
                .set(statusEnum.getKey().equals(ExamineStatusEnum.OK.getKey())
                        || statusEnum.getKey().equals(ExamineStatusEnum.FAIL.getKey()),
                        GoodsPurchase::getExamineTime, DateUtil.date())
                .eq(GoodsPurchase::getId, id)
                .eq(GoodsPurchase::getCompanyWechatId, companyId)
                .update();

        //审核通过加库存操作
        if (statusEnum.getKey().equals(ExamineStatusEnum.OK.getKey())) {
            jxGoodsLogic.addStock(id);

        }
    }

    private void checkCodeQty(GoodsPurchaseItem item, Map<String, List<GoodsMaterialItem>> materialItemGroupMap, Map<String, List<GoodsPurchaseCode>> codeGroupMap) {
        List<GoodsMaterialItem> materialItems = materialItemGroupMap.get(item.getGoodsMaterialId());
        for (GoodsMaterialItem materialItem : materialItems) {
            int totalNeedQty = item.getQty() * materialItem.getQty();

            int codeQty = 0;
            List<GoodsPurchaseCode> codeList = codeGroupMap.get(item.getId() + "-" + materialItem.getId());
            if (CollectionUtil.isNotEmpty(codeList)) {
                codeQty = codeList.stream().mapToInt(GoodsPurchaseCode::getCodeQty).sum();
            }

            if (codeQty != totalNeedQty) {
                throw new RemoteServiceException("\"" + item.getGoodsMaterialName() + "\"商品所需要条码数量与物料类型: \""
                        + BaseEnum.keyToEnumNotNull(GoodsMaterialTypeEnum.class, materialItem.getType()).getRemark() + "\" 物料名称: \""
                        + materialItem.getName() + "\"条码数量不一致");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void confirm(String id, ExamineStatusEnum statusEnum) throws InterruptedException {
        this.commonHandlePurchase(id, statusEnum);
    }

    @Transactional(rollbackFor = Exception.class)
    public void itemAddCode(GoodsPurchaseItemBean itemBean, AdminUserCom adminUser) {

        String companyId = null;
        if (Objects.nonNull(adminUser.getAdminCompanyWechat())) {
            companyId = adminUser.getAdminCompanyWechat().getCompanyWechatId();
        }

        if (CollectionUtil.isEmpty(itemBean.getCodeList())) {
            throw new RemoteServiceException("条码记录不为空");
        }

        GoodsPurchaseCode purchaseCode = itemBean.getCodeList().get(0);

        if (StringUtils.isBlank(purchaseCode.getGoodsMaterialItemId())) {
            throw new RemoteServiceException("商品子物料信息不能为空");
        }

        if (StringUtils.isBlank(purchaseCode.getCode())) {
            throw new RemoteServiceException("条码不为空");
        }
        // 去前后空
        purchaseCode.setCode(StrUtil.trim(purchaseCode.getCode()));

        if (Objects.isNull(purchaseCode.getCodeQty()) || purchaseCode.getCodeQty() < 0) {
            throw new RemoteServiceException("请填写有效的数量");
        }

        if (StringUtils.isNotBlank(purchaseCode.getId())) {
            GoodsPurchaseCode oldPurchaseCode = goodsPurchaseCodeService.getById(purchaseCode.getId());
            if (Objects.isNull(oldPurchaseCode)) {
                throw new RemoteServiceException("编辑的条码记录编号有误");
            }
            if (!oldPurchaseCode.getGoodsPurchaseId().equals(purchaseCode.getGoodsPurchaseId())) {
                throw new RemoteServiceException("编辑的条码记录商品入库单号有误");
            }
        }

        GoodsPurchase purchase = goodsPurchaseService.lambdaQuery()
                .eq(GoodsPurchase::getId, purchaseCode.getGoodsPurchaseId())
                .eq(GoodsPurchase::getCompanyWechatId, companyId)
                .eq(GoodsPurchase::getStatus, ExamineStatusEnum.SAVE.getKey())
                .one();

        if (Objects.isNull(purchase)) {
            throw new RemoteServiceException("商品采购入库单不存在");
        }

        if (!purchase.getJoinCode().equals("CODE")) {
            throw new RemoteServiceException("单据不需要关联条码");
        }

        GoodsPurchaseItem purchaseItem = goodsPurchaseItemService.lambdaQuery()
                .eq(GoodsPurchaseItem::getGoodsPurchaseId, purchase.getId())
                .eq(GoodsPurchaseItem::getGoodsMaterialId, purchaseCode.getGoodsMaterialId())
                .one();

        if (Objects.isNull(purchaseItem)) {
            throw new RemoteServiceException("商品记录不存在");
        }

        GoodsMaterialItem materialItem = goodsMaterialItemService.lambdaQuery()
                .eq(GoodsMaterialItem::getGoodsMaterialId, purchaseCode.getGoodsMaterialId())
                .eq(GoodsMaterialItem::getId, purchaseCode.getGoodsMaterialItemId())
                .one();

        if (Objects.isNull(materialItem)) {
            throw new RemoteServiceException("商品子物料不存在");
        }

        if (StringUtils.isBlank(purchaseCode.getId())) {
            GoodsPurchaseCode existCode = goodsPurchaseCodeService.lambdaQuery()
                    .eq(GoodsPurchaseCode::getGoodsPurchaseId, purchase.getId())
                    .eq(GoodsPurchaseCode::getGoodsPurchaseItemId, purchaseItem.getId())
                    .eq(GoodsPurchaseCode::getGoodsMaterialId, materialItem.getGoodsMaterialId())
                    .eq(GoodsPurchaseCode::getGoodsMaterialItemId, materialItem.getId())
                    .eq(GoodsPurchaseCode::getCode, StrUtil.trim(purchaseCode.getCode()))
                    .eq(GoodsPurchaseCode::getUniqueCode, IsYesNoEnum.NO.getKey())
                    .one();
            if (Objects.nonNull(existCode)) {
                // 发现存在相同物料类型、物料名称、条码就相加数量并注入相同的条码记录id
                purchaseCode.setId(existCode.getId())
                        .setCodeQty(existCode.getCodeQty() + purchaseCode.getCodeQty());
            }
        }

        purchaseCode.setGoodsPurchaseId(purchase.getId())
                .setGoodsPurchaseItemId(purchaseItem.getId())
                .setGoodsMaterialId(materialItem.getGoodsMaterialId())
                .setGoodsMaterialItemId(materialItem.getId())
                .setGoodsMaterialItemType(materialItem.getType())
                .setGoodsMaterialItemName(materialItem.getName())
                .setUniqueCode(materialItem.getUniqueCode());

        if (purchaseCode.getUniqueCode().equals(IsYesNoEnum.YES.getKey())) {
            // 一物一码检查商户全网唯一
            this.checkCompanyNetworkUniqueCode(purchase, purchaseCode, true);
        }

        purchaseCode.insertOrUpdate();

        // 统计条码数量
        this.computeImportCodeQty(purchase, purchaseItem);

    }

    private void checkCompanyNetworkUniqueCode(GoodsPurchase purchase, GoodsPurchaseCode purchaseCode, boolean checkCurPurchase) {
        Integer inCount = goodsCodeAccService.lambdaQuery()
                .eq(GoodsCodeAcc::getCompanyWechatId, purchase.getCompanyWechatId())
                .eq(GoodsCodeAcc::getMaterialCode, purchaseCode.getCode())
                .eq(GoodsCodeAcc::getStatus, CodeAccStatusEnum.GIVE.getKey())
                .eq(GoodsCodeAcc::getOrderType, CodeAccTypeEnum.PUR.getKey())
                .count();

        Integer outCount = goodsCodeAccService.lambdaQuery()
                .eq(GoodsCodeAcc::getCompanyWechatId, purchase.getCompanyWechatId())
                .eq(GoodsCodeAcc::getMaterialCode, purchaseCode.getCode())
                .eq(GoodsCodeAcc::getStatus, CodeAccStatusEnum.OUT.getKey())
                .eq(GoodsCodeAcc::getOrderType, CodeAccTypeEnum.OUT.getKey())
                .count();

        // 采购入库数量 - 采购退货数量
        int existCount = inCount - outCount;

        if (existCount > 0) {
            throw new RemoteServiceException("\"" + purchaseCode.getCode() + "\"条码为一物一码, 在条码库已存在记录");
        }

        if (checkCurPurchase) {
            Integer count = goodsPurchaseCodeService.lambdaQuery()
                    .eq(GoodsPurchaseCode::getGoodsPurchaseId, purchase.getId())
                    .eq(GoodsPurchaseCode::getCode, purchaseCode.getCode())
                    .ne(StringUtils.isNotBlank(purchaseCode.getId()), GoodsPurchaseCode::getId, purchaseCode.getId())
                    .count();
            if (count > 0) {
                throw new RemoteServiceException("物料类型: \""
                        + BaseEnum.keyToEnumNotNull(GoodsMaterialTypeEnum.class, purchaseCode.getGoodsMaterialItemType()).getRemark()
                        + "\" 物料名称: \"" + purchaseCode.getGoodsMaterialItemName() + "\" 条码为一物一码, 在当前采购入库单已存在记录");
            }
        }

        purchaseCode.setCodeQty(1);
    }

    private void computeImportCodeQty(GoodsPurchase purchase, GoodsPurchaseItem purchaseItem) {
        int insideCodeQty = 0;
        int outCodeQty = 0;
        int partsCodeQty = 0;
        List<GoodsPurchaseCode> purchaseCodeList = goodsPurchaseCodeService.lambdaQuery()
                .eq(GoodsPurchaseCode::getGoodsPurchaseId, purchase.getId())
                .eq(GoodsPurchaseCode::getGoodsPurchaseItemId, purchaseItem.getId())
                .eq(GoodsPurchaseCode::getGoodsMaterialId, purchaseItem.getGoodsMaterialId())
                .list();
        Map<String, List<GoodsPurchaseCode>> codeGroupMap = purchaseCodeList.stream()
                .collect(Collectors.groupingBy(GoodsPurchaseCode::getGoodsMaterialItemType));
        for (Map.Entry<String, List<GoodsPurchaseCode>> entry : codeGroupMap.entrySet()) {
            if (entry.getKey().equals(GoodsMaterialTypeEnum.INSIDE.getKey())) {
                insideCodeQty = entry.getValue().stream().mapToInt(GoodsPurchaseCode::getCodeQty).sum();
            } else if (entry.getKey().equals(GoodsMaterialTypeEnum.OUT.getKey())) {
                outCodeQty = entry.getValue().stream().mapToInt(GoodsPurchaseCode::getCodeQty).sum();
            } else {
                partsCodeQty = entry.getValue().stream().mapToInt(GoodsPurchaseCode::getCodeQty).sum();
            }
        }

        goodsPurchaseItemService.lambdaUpdate()
                .set(GoodsPurchaseItem::getInsideCodeQty, insideCodeQty)
                .set(GoodsPurchaseItem::getOutCodeQty, outCodeQty)
                .set(GoodsPurchaseItem::getPartsCodeQty, partsCodeQty)
                .eq(GoodsPurchaseItem::getId, purchaseItem.getId())
                .update();
    }

    @Transactional(rollbackFor = Exception.class)
    public void itemDelCode(String id, String codeId, AdminUserCom adminUser) {
        String companyId = null;
        if (Objects.nonNull(adminUser.getAdminCompanyWechat())) {
            companyId = adminUser.getAdminCompanyWechat().getCompanyWechatId();
        }

        GoodsPurchase purchase = goodsPurchaseService.lambdaQuery()
                .eq(GoodsPurchase::getId, id)
                .eq(GoodsPurchase::getCompanyWechatId, companyId)
                .eq(GoodsPurchase::getStatus, ExamineStatusEnum.SAVE.getKey())
                .one();

        if (Objects.isNull(purchase)) {
            throw new RemoteServiceException("商品采购入库单据已发生变更, 删除条码失败");
        }

        goodsPurchaseCodeService.lambdaUpdate()
                .eq(GoodsPurchaseCode::getId, codeId)
                .eq(GoodsPurchaseCode::getGoodsPurchaseId, id)
                .remove();
    }

    @Transactional(rollbackFor = Exception.class)
    public void itemImportCode(MultipartFile file, String purchaseItemId, AdminUserCom adminUser) throws IOException {
        String companyWechatId = Objects.nonNull(adminUser.getAdminCompanyWechat()) ? adminUser.getAdminCompanyWechat().getCompanyWechatId() : null;

        List<Object> objects = ExcelUtils.importExcel(file);
        List<GoodsPurchaseCode> codeList = new ArrayList<>();

        if (CollectionUtil.isEmpty(objects)) {
            throw new RemoteServiceException("导入条码记录为0, 请检查");
        }

        // 查找入库商品明细记录
        GoodsPurchaseItem purchaseItem = goodsPurchaseItemService.lambdaQuery()
                .eq(GoodsPurchaseItem::getId, purchaseItemId)
                .one();

        if (Objects.isNull(purchaseItem)) {
            throw new RemoteServiceException("商品记录不存在, 请检查");
        }

        // 查找入库单记录
        GoodsPurchase goodsPurchase = goodsPurchaseService.lambdaQuery()
                .eq(GoodsPurchase::getId, purchaseItem.getGoodsPurchaseId())
                .eq(GoodsPurchase::getCompanyWechatId, companyWechatId)
                .eq(GoodsPurchase::getStatus, ExamineStatusEnum.SAVE.getKey())
                .one();

        if (Objects.isNull(goodsPurchase)) {
            throw new RemoteServiceException("商品采购入库单状态非保存状态, 请检查");
        }

        if (!goodsPurchase.getJoinCode().equals("CODE")) {
            throw new RemoteServiceException("单据不需要关联条码");
        }

        // 查找商品子物料列表
        List<GoodsMaterialItem> materialItemList = goodsMaterialItemService.lambdaQuery()
                .eq(GoodsMaterialItem::getGoodsMaterialId, purchaseItem.getGoodsMaterialId())
                .list();

        Map<String, GoodsMaterialItem> materialItemMap = materialItemList.stream()
                .collect(Collectors.toMap(v -> v.getType() + "-" + v.getName(), Function.identity()));

        Map<String, List<GoodsMaterialItem>> materialItemGroupMap = materialItemList.stream()
                .collect(Collectors.groupingBy(GoodsMaterialItem::getGoodsMaterialId));

        // 查找入库商品条码列表
        List<GoodsPurchaseCode> purchaseCodeList = goodsPurchaseCodeService.lambdaQuery()
                .eq(GoodsPurchaseCode::getGoodsPurchaseId, goodsPurchase.getId())
                .eq(GoodsPurchaseCode::getGoodsPurchaseItemId, purchaseItem.getId())
                .eq(GoodsPurchaseCode::getGoodsMaterialId, purchaseItem.getGoodsMaterialId())
                .list();

        Map<String, GoodsPurchaseCode> purchaseCodeMap = purchaseCodeList.stream()
                .collect(Collectors.toMap(v -> v.getGoodsMaterialItemType() + "-"
                        + v.getGoodsMaterialItemName() + "-" + v.getCode(), Function.identity()));

        for (int i = 0; i < objects.size(); i++) {
            List<Object> row = (List<Object>) objects.get(i);
            if (Objects.isNull(row.get(0))) {
                throw new RemoteServiceException("第" + (i + 1) + "行, 物料类型不能为空");
            }
            if (Objects.isNull(row.get(1))) {
                throw new RemoteServiceException("第" + (i + 1) + "行, 物料名称不能为空");
            }
            if (Objects.isNull(row.get(2))) {
                throw new RemoteServiceException("第" + (i + 1) + "行, 条码不能为空");
            }
            if (Objects.isNull(row.get(3))) {
                throw new RemoteServiceException("第" + (i + 1) + "行, 数量不能为空");
            }

            String typeStr = (String) row.get(0);
            String nameStr = (String) row.get(1);
            String codeStr = (String) row.get(2);
            String qtyStr = (String) row.get(3);

            String type = "";
            if (GoodsMaterialTypeEnum.INSIDE.getRemark().equals(StrUtil.trimToEmpty(typeStr))) {
                type = GoodsMaterialTypeEnum.INSIDE.getKey();
            } else if (GoodsMaterialTypeEnum.OUT.getRemark().equals(StrUtil.trimToEmpty(typeStr))) {
                type = GoodsMaterialTypeEnum.OUT.getKey();
            } else if (GoodsMaterialTypeEnum.PARTS.getRemark().equals(StrUtil.trimToEmpty(typeStr))) {
                type = GoodsMaterialTypeEnum.PARTS.getKey();
            }

            if (StringUtils.isBlank(type)) {
                throw new RemoteServiceException("第" + (i + 1) + "行, 物料类型匹配不到子物料");
            }

            nameStr = StrUtil.trimToEmpty(nameStr);
            if (!materialItemMap.containsKey(type + "-" + nameStr)) {
                throw new RemoteServiceException("第" + (i + 1) + "行, 物料名称匹配不到子物料");
            }

            if (StringUtils.isBlank(codeStr)) {
                throw new RemoteServiceException("第" + (i + 1) + "行, 条码不能为空");
            }
            // 去前后空
            codeStr = StrUtil.trim(codeStr);

            if (StringUtils.isBlank(qtyStr) || Integer.parseInt(qtyStr) < 0) {
                throw new RemoteServiceException("第" + (i + 1) + "行, 请填写有效数量");
            }

            GoodsMaterialItem materialItem = materialItemMap.get(type + "-" + nameStr);
            int qty = Integer.parseInt(qtyStr);

            GoodsPurchaseCode purchaseCode = new GoodsPurchaseCode();

            if (purchaseCodeMap.containsKey(materialItem.getType() + "-" + materialItem.getName() + "-" + codeStr)) {
                // 存在相同物料类型、物料名称、条码并且非一物一码就相加数量
                GoodsPurchaseCode code = purchaseCodeMap.get(materialItem.getType() + "-" + materialItem.getName() + "-" + codeStr);
                if (code.getUniqueCode().equals(IsYesNoEnum.NO.getKey())) {
                    purchaseCode.setId(code.getId());
                    qty = code.getCodeQty() + qty;
                }
            }

            purchaseCode.setGoodsPurchaseId(goodsPurchase.getId())
                    .setGoodsPurchaseItemId(purchaseItem.getId())
                    .setGoodsMaterialId(materialItem.getGoodsMaterialId())
                    .setGoodsMaterialItemId(materialItem.getId())
                    .setGoodsMaterialItemType(materialItem.getType())
                    .setGoodsMaterialItemName(materialItem.getName())
                    .setUniqueCode(materialItem.getUniqueCode())
                    .setCode(codeStr)
                    .setCodeQty(qty);

            // 检查一物一码
            if (materialItem.getUniqueCode().equals(IsYesNoEnum.YES.getKey())) {
                this.checkCompanyNetworkUniqueCode(goodsPurchase, purchaseCode, true);
            }

            codeList.add(purchaseCode);
        }

        // 检查是否存在一物一码的重复导入
        if (CollectionUtil.isNotEmpty(codeList)) {
            List<GoodsPurchaseCode> purchaseCodes = codeList.stream()
                    .filter(v -> v.getUniqueCode().equals(IsYesNoEnum.YES.getKey()))
                    .collect(Collectors.toList());
            for (GoodsPurchaseCode purchaseCode : purchaseCodes) {
                int count = 0;
                for (GoodsPurchaseCode code : codeList) {
                    if (code.getUniqueCode().equals(IsYesNoEnum.NO.getKey())) {
                        continue;
                    }
                    if (code.getCode().equals(purchaseCode.getCode())) {
                        count++;
                    }
                    if (count > 1) {
                        throw new RemoteServiceException("物料类型: \""
                                + BaseEnum.keyToEnumNotNull(GoodsMaterialTypeEnum.class, purchaseCode.getGoodsMaterialItemType()).getRemark()
                                + "\" 物料名称: \"" + purchaseCode.getGoodsMaterialItemName() + "\" 条码为一物一码, 导入模板有重复记录");
                    }
                }
            }
        }

        goodsPurchaseCodeService.saveOrUpdateBatch(codeList);

        purchaseCodeList = goodsPurchaseCodeService.lambdaQuery()
                .eq(GoodsPurchaseCode::getGoodsPurchaseId, goodsPurchase.getId())
                .eq(GoodsPurchaseCode::getGoodsPurchaseItemId, purchaseItem.getId())
                .eq(GoodsPurchaseCode::getGoodsMaterialId, purchaseItem.getGoodsMaterialId())
                .list();

        Map<String, List<GoodsPurchaseCode>> codeGroupMap = purchaseCodeList.stream()
                .collect(Collectors.groupingBy(v -> v.getGoodsPurchaseItemId() + "-" + v.getGoodsMaterialItemId()));

        // 检查条码数量
        this.checkCodeQty(purchaseItem, materialItemGroupMap, codeGroupMap);

        // 计算导入条码数量
        this.computeImportCodeQty(goodsPurchase, purchaseItem);
    }

    public void del(String id) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        boolean remove = goodsPurchaseService.lambdaUpdate()
                .eq(GoodsPurchase::getId, id)
                .eq(GoodsPurchase::getCompanyWechatId, adminUser.getAdminCompanyWechat().getCompanyWechatId())
                .eq(GoodsPurchase::getStatus, ExamineStatusEnum.SAVE.getKey())
                .remove();
        if (remove) {
            goodsPurchaseItemService.lambdaUpdate()
                    .eq(GoodsPurchaseItem::getGoodsPurchaseId, id)
                    .remove();
            goodsPurchaseCodeService.lambdaUpdate()
                    .eq(GoodsPurchaseCode::getGoodsPurchaseId, id)
                    .remove();
        }
    }
}
