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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
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.msg.ScmMsgConstants;
import com.hzs.common.core.enums.EPresaleStatus;
import com.hzs.common.core.enums.EYesNo;
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.ext.SaOrderExt;
import com.hzs.common.domain.scm.ic.IcAvailableNum;
import com.hzs.common.domain.scm.ic.IcAvailableSpecs;
import com.hzs.common.domain.scm.ic.ext.IcAvailableNumExt;
import com.hzs.common.domain.scm.ic.ext.IcOnHandNumExt;
import com.hzs.common.domain.scm.pub.ScmItemSpecs;
import com.hzs.common.domain.scm.sale.IcDelSaleLog;
import com.hzs.sale.product.IProductServiceApi;
import com.hzs.sale.product.dto.ProductDTO;
import com.hzs.scm.ic.mapper.IcAvailableNumMapper;
import com.hzs.scm.ic.mapper.IcAvailableSpecsMapper;
import com.hzs.scm.ic.param.AvailableNum;
import com.hzs.scm.ic.service.IIcAvailableNumService;
import com.hzs.scm.ic.service.IIcAvailableSpecsService;
import com.hzs.scm.sale.service.IIcDelSaleLogService;
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.util.*;

/**
 * <p>
 * 可用量 服务实现类
 * </p>
 *
 * @author hzs
 * @since 2023-12-09
 */
@Service
public class IcAvailableNumServiceImpl extends ServiceImpl<IcAvailableNumMapper, IcAvailableNum> implements IIcAvailableNumService {

    @Autowired
    private RedisService redisService;

    @Autowired
    private IIcAvailableSpecsService availableSpecsService;

    @Autowired
    private IIcDelSaleLogService delSaleLogService;

    @Autowired
    private IcAvailableSpecsMapper availableSpecsMapper;

    @DubboReference
    private IProductServiceApi productServiceApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void mergeIcAvailableNumByIcOnHandNum(List<IcOnHandNumExt> onHandNumList, Long pkMember) {
        try {
            List<IcAvailableSpecs> saveAvailableSpecsList = new ArrayList<>();
            for (IcOnHandNumExt icOnHandNum : onHandNumList) {
                IcAvailableNum icAvailableNum = IcAvailableNum.builder()
                        .pkCorp(icOnHandNum.getPkCorp())
                        .pkCubasdoc(icOnHandNum.getPkCubasdoc())
                        .pkProductBas(icOnHandNum.getPkProductBas())
                        .pkProduct(icOnHandNum.getPkProduct())
                        .pkUnit(icOnHandNum.getPkUnit())
                        .pkStorehouse(icOnHandNum.getPkStorehouse())
                        .availableNum(icOnHandNum.getNonhandnum())
                        .build();
                icAvailableNum.setPkCountry(icOnHandNum.getPkCountry());
                icAvailableNum.setPkCreator(pkMember);
                // 查询现存量表，是否存在现存量
                List<IcAvailableNumExt> availableNumList = baseMapper.queryIcAvailableNumByCondition(icOnHandNum, icOnHandNum.getScmItemSpecsList());
                // 可用量量流水
                List<IcAvailableSpecs> availableSpecsList = packageIcOnHandItemList(pkMember, icOnHandNum.getScmItemSpecsList(), icAvailableNum);
                updateOrInsertAvailableNum(availableNumList, icAvailableNum, availableSpecsList);
                for (IcAvailableSpecs availableSpecs : availableSpecsList) {
                    availableSpecs.setPkAvailableNum(icAvailableNum.getPkId());
                }
                if(availableSpecsList.size() >0){
                    saveAvailableSpecsList.addAll(availableSpecsList);
                }
            }
            if (saveAvailableSpecsList.size() > 0) {
                // 更新保存
                availableSpecsService.mergeIcAvailableSpecsByList(saveAvailableSpecsList);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void mergeIcAvailableNumByOrder(SaOrderExt saOrderExt) {
        // 根据订单回退可用量
        // 根据仓库查询公司、查询产品基本信息
        // 根据订单封装现存量参数，使用统一方法
        List<IcOnHandNumExt> onHandNumExtList = baseMapper.queryAvailableNumByOrder(saOrderExt);
        List<IcOnHandNumExt> updateHandNumList = new ArrayList<>();
        for (IcOnHandNumExt onHandNumExt : onHandNumExtList) {
            if(onHandNumExt.getPkProductBas() == null){
                continue;
            }
            if(saOrderExt.getDeductFlag() != null && saOrderExt.getDeductFlag()){
                onHandNumExt.setNonhandnum(onHandNumExt.getNonhandnum().negate());
            }
            String[] specsIsArr = onHandNumExt.getSpecsNameId().split(",");
            // 查询规格
            int[] pkSpecsArr = Arrays.stream(specsIsArr).mapToInt(Integer::parseInt).toArray();
            List<ScmItemSpecs> availableSpecsList = availableSpecsMapper.queryAvailableSpecs(pkSpecsArr);
            onHandNumExt.setScmItemSpecsList(availableSpecsList);
            updateHandNumList.add(onHandNumExt);
        }
        mergeIcAvailableNumByIcOnHandNum(updateHandNumList, saOrderExt.getPkModified());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertIcAvailableNumByParam(AvailableNum availableNum, Long pkMember) {
        try {
            IcAvailableNum icAvailableNum = BeanUtil.copyProperties(availableNum, IcAvailableNum.class);
            icAvailableNum.setPkCreator(pkMember);
            save(icAvailableNum);
            List<IcAvailableSpecs> availableSpecsList = packageIcOnHandItemList(pkMember, availableNum.getScmItemSpecsList(), icAvailableNum);
            if (availableSpecsList.size() > 0) {
                // 更新保存
                availableSpecsService.mergeIcAvailableSpecsByList(availableSpecsList);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private List<IcAvailableSpecs> packageIcOnHandItemList(Long pkMember, List<?> scmItemSpecsList, IcAvailableNum availableNum) {
        // 现存量流水
        List<IcAvailableSpecs> availableSpecsList = new ArrayList<>();
        // 现存量规格表
        if (CollectionUtil.isNotEmpty(scmItemSpecsList)) {
            for (Object scmItemSpecs : scmItemSpecsList) {
                IcAvailableSpecs icOnHandSpecs = IcAvailableSpecs.builder()
                        .pkAvailableNum(availableNum.getPkId())
                        .pkSpecsType(ReflectUtils.invokeGetter(scmItemSpecs, ScmFieldConstants.PK_SPECS_TYPE))
                        .pkSpecs(ReflectUtils.invokeGetter(scmItemSpecs, ScmFieldConstants.PK_SPECS))
                        .specsName(ReflectUtils.invokeGetter(scmItemSpecs, ScmFieldConstants.SPECS_NAME))
                        .build();
                icOnHandSpecs.setPkCountry(availableNum.getPkCountry());
                icOnHandSpecs.setPkCreator(pkMember);
                availableSpecsList.add(icOnHandSpecs);
            }
        }
        return availableSpecsList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDeductIcAvailableNumByGeneralOut(IcAvailableNum availableNum, Long pkMember) {
        String availableNumLock = CacheConstants.IC_AVAILABLE_NUM_LOCK + availableNum.getPkId();
        try {
            availableNum.setModifiedTime(DateUtils.currentDateTime());
            availableNum.setPkModified(pkMember);
            if (!redisService.lockKeyOnce(availableNumLock)) {
                throw new RuntimeException(ScmMsgConstants.BILL_NOT_OPERATION);
            }
            // 更新订单表
            updateById(availableNum);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDeductIcAvailableNumByList(List<IcAvailableNumExt> availableNumList) {
        List<String> availableKeyList = new ArrayList<>();
        IcDelSaleLog icDelSaleLog = IcDelSaleLog.builder()
                .acceptParam(JSONUtil.toJsonStr(availableNumList))
                .successStatus(EYesNo.YES.getIntValue())
                .sourceCode(availableNumList.get(0).getOrderCode())
                .billType(2)
                .build();
        icDelSaleLog.setPkCreator(availableNumList.get(0).getPkModified());
        icDelSaleLog.setPkCountry(availableNumList.get(0).getPkCountry());
        for (IcAvailableNum availableNum : availableNumList) {
            availableKeyList.add(CacheConstants.IC_AVAILABLE_NUM_LOCK + availableNum.getPkId());
        }
        try {
            redisService.lockKeyByList(availableKeyList);
            // 拆分 拆为预售和非预售 验证预售品是否存在现存量
            List<IcAvailableNumExt> updateAvailableNumList = new ArrayList<>();
            // 新增可用量List
            List<IcAvailableNumExt> inserAvailableNumList = new ArrayList<>();
            List<IcAvailableNumExt> updateWaresList = new ArrayList<>();
            for (IcAvailableNumExt availableNumExt : availableNumList) {
                List<IcAvailableNumExt> icAvailableNumExtList = baseMapper.queryAvailableNumByAvaliable(availableNumExt);
                if (icAvailableNumExtList != null && icAvailableNumExtList.size() >0) {
                    availableNumExt.setPkId(icAvailableNumExtList.get(0).getPkId());
                    updateAvailableNumList.add(availableNumExt);
                    if(ComputeUtil.compareValue(availableNumExt.getAvailableNum(), icAvailableNumExtList.get(0).getAvailableNum())){
                        updateWaresList.add(availableNumExt);
                    }
                }else if(EPresaleStatus.PRESALE.getValue() == availableNumExt.getPreSaleStatus()) {
                    inserAvailableNumList.add(availableNumExt);
                }else{
                    // 非预售产品可用量不足更新产品为下架或者预售
                    updateWaresList.add(availableNumExt);
                }
            }
            if(updateAvailableNumList.size() >0) {
                baseMapper.mergeIcAvailableNumByIcOnHandNum(updateAvailableNumList);
            }
            if(inserAvailableNumList.size()>0){
                for (IcAvailableNumExt availableNumExt : inserAvailableNumList) {
                    IcAvailableNum icAvailableNum = IcAvailableNum.builder()
                            .pkCorp(availableNumExt.getPkCorp())
                            .pkCubasdoc(availableNumExt.getPkCubasdoc())
                            .pkProductBas(availableNumExt.getPkProductBas())
                            .pkProduct(availableNumExt.getPkProduct())
                            .pkUnit(availableNumExt.getPkUnit())
                            .pkStorehouse(availableNumExt.getPkStorehouse())
                            .availableNum(availableNumExt.getAvailableNum().negate())
                            .build();
                    // 根据产品id查询产品基本主键
                    icAvailableNum.setPkCountry(availableNumExt.getPkCountry());
                    icAvailableNum.setPkCreator(availableNumExt.getPkModified());
                    List<IcAvailableSpecs> availableSpecsList = packageIcOnHandItemList(availableNumExt.getPkModified(), availableNumExt.getScmItemSpecsList(), icAvailableNum);
                    save(icAvailableNum);
                    for (IcAvailableSpecs availableSpecs : availableSpecsList) {
                        availableSpecs.setPkAvailableNum(icAvailableNum.getPkId());
                        availableSpecs.setPkCreator(icAvailableNum.getPkCreator());
                        availableSpecs.setPkCountry(icAvailableNum.getPkCountry());
                    }
                    if(availableSpecsList.size() >0){
                        // 更新保存
                        availableSpecsService.mergeIcAvailableSpecsByList(availableSpecsList);
                    }
                }
            }
            if(updateWaresList.size() >0){
                try {
                    // 更新状态
                    List<ProductDTO> productDtoList = new ArrayList<>();
                    for (IcAvailableNumExt availableNumExt : updateWaresList) {
                        if(availableNumExt.getPkProduct() != null) {
                            ProductDTO productDTO = new ProductDTO();
                            productDTO.setProductId(availableNumExt.getPkProduct());
                            productDtoList.add(productDTO);
                        }
                    }
                    if(productDtoList.size() >0) {
                        productServiceApi.updateWaresPreSaleStatus(productDtoList);
                    }
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            icDelSaleLog.setErrorMsg(e.getMessage());
            icDelSaleLog.setSuccessStatus(EYesNo.NO.getIntValue());
            throw new RuntimeException(e);
        } finally {
            // 记录日志
            try {
                delSaleLogService.save(icDelSaleLog);
            } catch (Exception e) {
                e.printStackTrace();
            }
            redisService.unlockByList(availableKeyList);
        }
    }

    @Override
    public List<IcAvailableNumExt> queryAvailableNumByProduct(List<IcAvailableNum> availableNumList) {
        return baseMapper.queryAvailableNumByProduct(availableNumList);
    }

    @Override
    public List<IcAvailableNumExt> queryAvailableNumByCondition(AvailableNum availableNum) {
        return baseMapper.queryAvailableNumByCondition(availableNum);
    }

    /*
     * @description: 更新或修改现存量表
     * @author: sui q
     * @date: 2023/11/22 15:29
     * @param: null null
     **/
    private void updateOrInsertAvailableNum(List<IcAvailableNumExt> availableNumList, IcAvailableNum availableNum, List<IcAvailableSpecs> availableSpecsList) {
        Map<String, IcAvailableNum> availableNumMap = new HashMap<>();
        if (availableNumList != null && availableNumList.size() > 0) {
            for (IcAvailableNumExt icAvailableNumExt : availableNumList) {
                availableNumMap.put(icAvailableNumExt.getSpecsName(), icAvailableNumExt);
            }
        }
        StringBuilder key = new StringBuilder();
        if(availableSpecsList.size() >0) {
            for (int i = 0; i < availableSpecsList.size(); i++) {
                IcAvailableSpecs scmItemSpecs = availableSpecsList.get(i);
                key.append(scmItemSpecs.getPkSpecs());
                if (i < availableSpecsList.size() - 1) {
                    key.append(",");
                }
            }
        }else {
            key.append("x123");
        }
        if (availableNumMap.containsKey(key.toString())){
            updateAvailableNum(availableNumMap.get(key.toString()), availableNum);
        } else {
            save(availableNum);
        }
    }

    private void updateAvailableNum(IcAvailableNum oldAvailableNum, IcAvailableNum availableNum) {
        String key = CacheConstants.IC_AVAILABLE_NUM_LOCK + availableNum.getPkId();
        try {
            if (!redisService.lockKeyOnce(key)) {
                throw new RuntimeException(ScmMsgConstants.BILL_NOT_OPERATION);
            }
            if(availableNum.getPkCubasdoc() != null){
                oldAvailableNum.setPkCubasdoc(availableNum.getPkCubasdoc());
            }
            oldAvailableNum.setAvailableNum(availableNum.getAvailableNum());
            oldAvailableNum.setPkModified(availableNum.getPkCreator());
            oldAvailableNum.setModifiedTime(DateUtils.currentDateTime());
            if (baseMapper.updateAvailableNumByNum(oldAvailableNum) <= 0) {
                throw new RuntimeException(ScmMsgConstants.IC_AVAILABLE_NUM_NOT_EMPTY);
            }
            availableNum.setPkId(oldAvailableNum.getPkId());
        } finally {
            redisService.unlock(key);
        }
    }
}
