package com.hzs.scm.store.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzs.common.core.constant.CacheConstants;
import com.hzs.common.core.constant.ScmFieldConstants;
import com.hzs.common.core.constant.SystemFieldConstants;
import com.hzs.common.core.constant.msg.ScmMsgConstants;
import com.hzs.common.core.enums.EScmOrderType;
import com.hzs.common.core.service.RedisService;
import com.hzs.common.core.utils.ComputeUtil;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.core.utils.reflect.ReflectUtils;
import com.hzs.common.domain.sale.classify.BdSpecs;
import com.hzs.common.domain.sale.ext.SaDeliverItemsExt;
import com.hzs.common.domain.scm.ic.IcOnHandNum;
import com.hzs.common.domain.scm.ic.IcOnHandNumB;
import com.hzs.common.domain.scm.ic.IcOnHandSpecs;
import com.hzs.common.domain.scm.ic.ext.IcOnHandNumExt;
import com.hzs.common.domain.scm.pub.ScmItemSpecs;
import com.hzs.common.domain.scm.sale.ext.IcSaleoutBExt;
import com.hzs.common.domain.scm.store.IcStoreHandNum;
import com.hzs.common.domain.scm.store.IcStoreHandNumB;
import com.hzs.common.domain.scm.store.IcStoreHandSpecs;
import com.hzs.common.domain.scm.store.IcStoreOutH;
import com.hzs.common.domain.scm.store.ext.IcStoreHandNumExt;
import com.hzs.common.domain.scm.store.ext.IcStoreOutBExt;
import com.hzs.common.domain.scm.store.ext.IcStoreOutHExt;
import com.hzs.sale.product.IProductServiceApi;
import com.hzs.scm.store.mapper.IcStoreHandNumMapper;
import com.hzs.scm.store.param.StoreHandNumParam;
import com.hzs.scm.store.service.IIcStoreHandNumBService;
import com.hzs.scm.store.service.IIcStoreHandNumService;
import com.hzs.scm.store.service.IIcStoreHandSpecsService;
import com.hzs.scm.store.service.IIcStoreOutBService;
import org.apache.dubbo.config.annotation.DubboReference;
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 hzs
 * @since 2024-05-16
 */
@Service
public class IcStoreHandNumServiceImpl extends ServiceImpl<IcStoreHandNumMapper, IcStoreHandNum> implements IIcStoreHandNumService {

    @DubboReference
    private IProductServiceApi productServiceApi;
    @Autowired
    private IIcStoreHandNumBService storeHandNumBiService;
    @Autowired
    private IIcStoreHandSpecsService storeHandSpecsService;
    @Autowired
    private RedisService redisService;

    @Override
    public List<IcStoreHandNumExt> queryIcStoreHandNumByCondition(StoreHandNumParam storeHandNumParam) {
        return baseMapper.queryDisIcStoreHandNumByCondition(storeHandNumParam);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void mergeIcStoreHandNumByStoreOut(List<IcStoreOutHExt> storeOutExtList, Integer orderType, Long pkMember) {
        // 收货时，就是取发送店铺
        // 加锁
        List<IcStoreHandNumB> saveOnHandNumbList = new ArrayList<>();
        List<IcStoreHandSpecs> saveOnHandSpecsList = new ArrayList<>();
        // 查询规格，处理规格
        List<Integer> querySpeceIdList = new ArrayList<>();
        for (IcStoreOutHExt storeOutExt : storeOutExtList) {
            for (IcStoreOutBExt icStoreOutBiExt : storeOutExt.getStoreOutBiExtList()) {
                String[] specsId = icStoreOutBiExt.getSpecsNameId().split(",");
                querySpeceIdList.addAll(Arrays.stream(specsId).map(Integer::valueOf).collect(Collectors.toList()));
            }
        }
        List<BdSpecs> specsList = productServiceApi.queryBdSpecsByIdList(querySpeceIdList).getData();
        Map<Integer, BdSpecs> specsMap = specsList.stream().collect(Collectors.toMap(BdSpecs::getPkId, bdSpecs -> bdSpecs));
        for (IcStoreOutHExt storeOutExt : storeOutExtList) {
            for (IcStoreOutBExt icStoreOutBiExt : storeOutExt.getStoreOutBiExtList()) {
                IcStoreHandNum icStoreHandNum = IcStoreHandNum.builder()
                        .pkProductBas(icStoreOutBiExt.getPkProductBas())
                        .pkProduct(icStoreOutBiExt.getPkProduct())
                        .pkMemberStore(storeOutExt.getPkSendStore())
                        .pkUnit(icStoreOutBiExt.getPkUnit())
                        .nonhandnum(BigDecimal.valueOf(icStoreOutBiExt.getQuantity()))
                        .build();
                icStoreHandNum.setPkCountry(storeOutExt.getPkCountry());
                icStoreHandNum.setPkCreator(pkMember);
                // 查询现存量表，是否存在现存量
                List<IcStoreHandNumExt> oldOnHandNumList = queryIcStoreHandNumByCondition(icStoreHandNum, icStoreOutBiExt.getSpecsNameId());
                List<IcStoreHandNumB> onhandNumBiList = new ArrayList<>();
                String[] specsId = icStoreOutBiExt.getSpecsNameId().split(",");
                List<ScmItemSpecs> scmItemSpecsList = new ArrayList<>();
                for (String pkSpecs : specsId) {
                    Integer key = Integer.parseInt(pkSpecs);
                    if(specsMap.containsKey(key)){
                        BdSpecs bdSpecs = specsMap.get(key);
                        ScmItemSpecs scmItemSpecs = ScmItemSpecs.builder()
                                .pkSpecs(bdSpecs.getPkId())
                                .pkSpecsType(bdSpecs.getPkSpecsType())
                                .specsName(bdSpecs.getSpecsName())
                                .build();
                        scmItemSpecsList.add(scmItemSpecs);
                    }
                }
                List<IcStoreHandSpecs> icOnHandSpecsList = packageIcStoreHandItemList(icStoreOutBiExt.getPkOrder(), icStoreOutBiExt.getPkOrderItems(), storeOutExt.getPkCountry(),
                        orderType, pkMember, onhandNumBiList, scmItemSpecsList, icStoreHandNum);
                // 用于更新可用量
                icStoreHandNum.setScmItemSpecsList(scmItemSpecsList);
                updateOrInsertStoreHandNum(oldOnHandNumList, icStoreHandNum);
                for (IcStoreHandSpecs icOnHandSpecs : icOnHandSpecsList) {
                    icOnHandSpecs.setPkOnhandnum(icStoreHandNum.getPkId());
                }
                saveOnHandSpecsList.addAll(icOnHandSpecsList);
                for(IcStoreHandNumB onHandNumB : onhandNumBiList){
                    onHandNumB.setPkOnhandnum(icStoreHandNum.getPkId());
                }
                saveOnHandNumbList.addAll(onhandNumBiList);
                // 现存量流水
            }
        }
        if (saveOnHandNumbList.size() > 0) {
            // 保存
            storeHandNumBiService.saveBatch(saveOnHandNumbList);
        }
        if (saveOnHandSpecsList.size() > 0) {
            // 更新保存
            storeHandSpecsService.mergeIcOnHandSpecsByList(saveOnHandSpecsList);
        }
    }

    private List<IcStoreHandNumExt> queryIcStoreHandNumByCondition(IcStoreHandNum icStoreHandNum, String pkSpecs){
        StoreHandNumParam storeHandNumParam = StoreHandNumParam.builder()
                .pkProduct(icStoreHandNum.getPkProduct())
                .pkCountry(icStoreHandNum.getPkCountry())
                .pkMemberStore(icStoreHandNum.getPkMemberStore())
                .pkSpecs(pkSpecs)
                .build();
        return baseMapper.queryIcStoreHandNumByCondition(storeHandNumParam);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deductIcStoreHandNumByStoreOut(IcStoreOutHExt storeOutExt, Integer orderType, Long pkMember) {
        // 根据明细表查询出产品、仓库内所有的批次信息，按照倒叙排列
        // 需要按照先进先出进行扣减，当前批次不够扣减下一个批次
        // 加锁
        List<IcStoreHandNumB> icOnHandNumbList = new ArrayList<>();
        for (IcStoreOutBExt storeOutBiExt : storeOutExt.getStoreOutBiExtList()) {
            // 根据仓库 产品id 规格 批次号查询是否已经存在，存在的话对数量进行修改
            // 现存量规格表
            // 现存量表
            IcStoreHandNum queryHandNum = IcStoreHandNum.builder()
                    .pkProduct(storeOutBiExt.getPkProduct())
                    .pkMemberStore(storeOutExt.getPkSendStore())
                    .build();
            queryHandNum.setPkCountry(storeOutExt.getPkCountry());
            // 查询现存量表，是否存在现存量
            List<IcStoreHandNumExt> oldOnHandNumList = queryIcStoreHandNumByCondition(queryHandNum, storeOutBiExt.getSpecsNameId());
            // 待扣减库存
            BigDecimal nNum = BigDecimal.valueOf(storeOutBiExt.getQuantity());
            List<IcStoreHandNum> deductOnHandNumList = new ArrayList<>();
            Date date = DateUtils.currentDateTime();
            for (IcStoreHandNum onHandNum : oldOnHandNumList) {
                onHandNum.setPkModified(pkMember);
                onHandNum.setModifiedTime(date);
                if(ComputeUtil.compareValue(onHandNum.getNonhandnum(), nNum)){
                    onHandNum.setNonhandnum(nNum.negate());
                    deductOnHandNumList.add(onHandNum);
                    nNum = BigDecimal.ZERO;
                    break;
                }else {
                    nNum = ComputeUtil.computeSubtract(nNum, onHandNum.getNonhandnum());
                    onHandNum.setNonhandnum(onHandNum.getNonhandnum().negate());
                    deductOnHandNumList.add(onHandNum);
                }
            }
            if(ComputeUtil.compareValue(nNum)){
                return Boolean.FALSE;
            }
            // 一行行更新，防止不同行用同一个批次
            updateOrInsertOnHandNum(deductOnHandNumList);
            for (IcStoreHandNum icOnHand : deductOnHandNumList) {
                // 现存量流水
                IcStoreHandNumB icOnHandNumB = IcStoreHandNumB.builder()
                        .pkOnhandnum(icOnHand.getPkId())
                        .orderType(orderType)
                        .pkSource(storeOutBiExt.getPkStoreoutH())
                        .pkSourceB(storeOutBiExt.getPkId())
                        .nnum(icOnHand.getNonhandnum())
                        .build();
                icOnHandNumB.setPkCountry(storeOutExt.getPkCountry());
                icOnHandNumB.setPkCreator(pkMember);
                icOnHandNumbList.add(icOnHandNumB);
            }
        }
        if (icOnHandNumbList.size() > 0) {
            // 保存
            storeHandNumBiService.saveBatch(icOnHandNumbList);
        }
        return Boolean.TRUE;
    }

    /*
     * @description: 更新或修改现存量表
     * @author: sui q
     * @date: 2023/11/22 15:29
     * @param: null null
     **/
    private void updateOrInsertOnHandNum(List<IcStoreHandNum> updOnHandNumList) {
        // 加锁
        List<String> keyList = new ArrayList<>();
        for (IcStoreHandNum icOnHandNum : updOnHandNumList) {
            String key = CacheConstants.IC_STORE_HAND_NUM_LOCK + icOnHandNum.getPkId();
            keyList.add(key);
        }
        try {
            if (!redisService.lockKeyByList(keyList)) {
                throw new RuntimeException(ScmMsgConstants.BILL_NOT_OPERATION);
            }
            if (baseMapper.mergeUpdateOnHandNumByNum(updOnHandNumList) < updOnHandNumList.size()) {
                throw new RuntimeException(ScmMsgConstants.IC_ON_HAND_NUM_NOT_EMPTY);
            }
        }finally {
            redisService.unlockByList(keyList);
        }
    }

    /*
     * @description: 更新或修改现存量表
     * @author: sui q
     * @date: 2023/11/22 15:29
     * @param: null null
     **/
    private void updateOrInsertStoreHandNum(List<IcStoreHandNumExt> oldOnHandNumList, IcStoreHandNum icOnHandNum) {
        Map<String, IcStoreHandNumExt> onHandNumMap = new HashMap<>();
        if (oldOnHandNumList != null && oldOnHandNumList.size() > 0) {
            for (IcStoreHandNumExt onHandNum : oldOnHandNumList) {
                onHandNumMap.put(onHandNum.getSpecsNameId(), onHandNum);
            }
        }
        String handKey = getStringKey(icOnHandNum.getScmItemSpecsList());
        // 存在修改
        if (onHandNumMap.containsKey(handKey)) {
            // 加锁
            IcStoreHandNum oldOnHandNum = onHandNumMap.get(handKey);
            icOnHandNum.setPkId(oldOnHandNum.getPkId());
            String key = CacheConstants.IC_STORE_HAND_NUM_LOCK + icOnHandNum.getPkId();
            try {
                if (!redisService.lockKeyOnce(key)) {
                    throw new RuntimeException(ScmMsgConstants.BILL_NOT_OPERATION);
                }
                oldOnHandNum.setNonhandnum(icOnHandNum.getNonhandnum());
                oldOnHandNum.setPkModified(icOnHandNum.getPkCreator());
                oldOnHandNum.setModifiedTime(DateUtils.currentDateTime());
                if (baseMapper.updateStoreHandNumByNum(oldOnHandNum) <= 0) {
                    throw new RuntimeException(ScmMsgConstants.IC_ON_HAND_NUM_NOT_EMPTY);
                }
            }finally {
                redisService.unlock(key);
            }
        } else {
            save(icOnHandNum);
        }
    }

    private String getStringKey(List<ScmItemSpecs> scmItemSpecsList) {
        if(scmItemSpecsList == null || scmItemSpecsList.size() == 0){
            return "x123";
        }
        StringBuilder handKey = new StringBuilder();
        for (int i = 0; i < scmItemSpecsList.size(); i++) {
            ScmItemSpecs scmItemSpecs = scmItemSpecsList.get(i);
            handKey.append(scmItemSpecs.getPkSpecs());
            if(i < scmItemSpecsList.size() - 1){
                handKey.append(",");
            }
        }
        return handKey.toString();
    }

    private List<IcStoreHandSpecs> packageIcStoreHandItemList(Long pkSource, Long pkSourceB, Integer pkCountry, Integer orderType, Long pkMember, List<IcStoreHandNumB> icOnHandNumbList,
                                                              List<ScmItemSpecs> scmItemSpecsList, IcStoreHandNum icOnHandNum) {
        List<IcStoreHandSpecs> icOnHandSpecsList = new ArrayList<>();
        // 现存量流水
        IcStoreHandNumB icOnHandNumB = IcStoreHandNumB.builder()
                .pkOnhandnum(icOnHandNum.getPkId())
                .orderType(orderType)
                .pkSource(pkSource)
                .pkSourceB(pkSourceB)
                .nnum(icOnHandNum.getNonhandnum())
                .build();
        icOnHandNumB.setPkCountry(pkCountry);
        icOnHandNumB.setPkCreator(pkMember);
        icOnHandNumbList.add(icOnHandNumB);
        // 现存量规格表
        if (CollectionUtil.isNotEmpty(scmItemSpecsList)) {
            for (ScmItemSpecs scmItemSpecs : scmItemSpecsList) {
                IcStoreHandSpecs icOnHandSpecs = IcStoreHandSpecs.builder()
                        .pkOnhandnum(icOnHandNum.getPkId())
                        .pkSpecsType(scmItemSpecs.getPkSpecsType())
                        .pkSpecs(scmItemSpecs.getPkSpecs())
                        .specsName(scmItemSpecs.getSpecsName())
                        .build();
                icOnHandSpecs.setPkCountry(pkCountry);
                icOnHandSpecs.setPkCreator(pkMember);
                icOnHandSpecsList.add(icOnHandSpecs);
            }
        }
        return icOnHandSpecsList;
    }
}
