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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
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.service.RedisService;
import com.hzs.common.core.utils.DateUtils;
import com.hzs.common.core.utils.reflect.ReflectUtils;
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.system.base.BdStorehouse;
import com.hzs.scm.ic.mapper.IcAvailableNumMapper;
import com.hzs.scm.ic.param.AvailableNum;
import com.hzs.scm.ic.service.IIcAvailableNumService;
import com.hzs.scm.ic.service.IIcAvailableSpecsService;
import com.hzs.system.base.ICountryServiceApi;
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.*;

/**
 * 可用量 服务实现类
 */
@Service
public class IcAvailableNumServiceImpl extends ServiceImpl<IcAvailableNumMapper, IcAvailableNum> implements IIcAvailableNumService {

    @Autowired
    private RedisService redisService;

    @Autowired
    private IIcAvailableSpecsService availableSpecsService;

    @DubboReference
    ICountryServiceApi countryServiceApi;

    @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 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
    public List<IcAvailableNumExt> queryAvailableNumByCondition(AvailableNum availableNum) {
        return baseMapper.queryAvailableNumByCondition(availableNum);
    }

    @Override
    public IcAvailableNum queryAvailableNumByCondition(Integer pkCountry, Integer pkProduct, List<Integer> speceIdList) {
        // 根据国家查询仓库
        BdStorehouse bdStorehouse = countryServiceApi.queryBdStorehouseByCountry(pkCountry).getData();
        if (bdStorehouse != null) {
            return baseMapper.queryAvailableNumBySpecsId(bdStorehouse.getPkId(), pkProduct, speceIdList);
        }
        return null;
    }

    /*
     * @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);
        }
    }
}
