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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzs.common.core.constant.CacheConstants;
import com.hzs.common.core.constant.SaOrderFieldConstants;
import com.hzs.common.core.constant.SystemFieldConstants;
import com.hzs.common.core.constant.msg.DocumentMsgConstants;
import com.hzs.common.core.constant.msg.ScmMsgConstants;
import com.hzs.common.core.enums.*;
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.domain.scm.general.IcGeneralOutB;
import com.hzs.common.domain.scm.general.IcGeneralOutH;
import com.hzs.common.domain.scm.general.ext.IcGeneralOutBExt;
import com.hzs.common.domain.scm.general.ext.IcGeneralOutHExt;
import com.hzs.common.domain.scm.pub.ScmItemSpecs;
import com.hzs.common.domain.scm.pub.ScmOrderApproveLog;
import com.hzs.common.domain.system.sys.SysUser;
import com.hzs.common.core.utils.TransactionUtils;
import com.hzs.scm.general.mapper.IcGeneralOutHMapper;
import com.hzs.scm.general.param.GeneralBParam;
import com.hzs.scm.general.param.GeneralParam;
import com.hzs.scm.general.service.IIcGeneralOutBService;
import com.hzs.scm.general.service.IIcGeneralOutHService;
import com.hzs.scm.ic.service.IIcOnHandNumService;
import com.hzs.scm.no.service.IScmBillNoService;
import com.hzs.scm.pub.component.ScmPubUtilTool;
import com.hzs.scm.pub.param.ItemSpecsParam;
import com.hzs.scm.pub.param.ScmApproveParam;
import com.hzs.scm.pub.service.IScmItemSpecsService;
import com.hzs.scm.pub.service.IScmOrderApproveLogService;
import com.hzs.system.base.ICurrencyServiceApi;
import com.hzs.system.base.dto.CurrencyDTO;
import com.hzs.system.sys.IUserServiceApi;
import com.hzs.system.sys.dto.ApprovalBusinessResultDTO;
import com.hzs.system.sys.dto.LoginUser;
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.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 其他出库单表头 服务实现类
 * </p>
 *
 * @author hzs
 * @since 2023-11-27
 */
@Service
public class IcGeneralOutHServiceImpl extends ServiceImpl<IcGeneralOutHMapper, IcGeneralOutH> implements IIcGeneralOutHService {

    @DubboReference
    private ICurrencyServiceApi currencyServiceApi;

    @DubboReference
    private IUserServiceApi userServiceApi;

    @Autowired
    private IScmBillNoService scmBillNoService;

    @Autowired
    private IScmItemSpecsService scmItemSpecsService;

    @Autowired
    private IIcGeneralOutBService generalOutBiService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IScmOrderApproveLogService scmOrderApproveLogService;

    @Autowired
    private IIcOnHandNumService onHandNumService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertGeneralOutByGeneralParam(GeneralParam generalParam, Long pkMember) {
        saveGeneralByParam(generalParam, pkMember);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateGeneralOutByGeneralParam(IcGeneralOutHExt generalOutExt, GeneralParam generalParam, Long pkMember) {
        // 更新规格明细表，先删除在新增 根据主表主键删除
        scmItemSpecsService.deleteItemSpecsById(EScmOrderType.GENERAL_OUT.getValue(), generalOutExt.getPkId(), pkMember);
        generalOutExt.setPkCorp(generalParam.getPkCorp());
        generalOutExt.setPkInCorp(generalParam.getPkInCorp());
        generalOutExt.setPkCustomer(generalParam.getPkCustomer());
        generalOutExt.setPkInWarehouse(generalParam.getPkInWarehouse());
        generalOutExt.setPkWarehouse(generalParam.getPkWarehouse());
        generalOutExt.setOrderDate(generalParam.getOrderDate());
        generalOutExt.setRemark(generalParam.getRemark());
        // 更新订单明细表 分为3部分 删除的 新增的 修改的
        List<IcGeneralOutB> generalOutbList = getGeneralItems(generalParam, pkMember, generalOutExt);
        // 重新处理订单明细，将订单明细分为 删除的、新增的、修改的
        List<IcGeneralOutBExt> icGeneralOutbExtList = generalOutExt.getGeneralOutbExtList();
        // 剩余的就是需要删除的
        Map<Long, IcGeneralOutBExt> generalOutbExtMap = icGeneralOutbExtList.stream().collect(Collectors.toMap(IcGeneralOutBExt::getPkId, generalOut->generalOut));
        List<IcGeneralOutB> insertGeneralItems = new ArrayList<>();
        List<IcGeneralOutB> updateGeneralItems = new ArrayList<>();
        List<ScmItemSpecs> saveScmItemSpecsList = new ArrayList<>();
        for (IcGeneralOutB generalOutB : generalOutbList) {
            if (generalOutB.getPkId() != null && generalOutbExtMap.containsKey(generalOutB.getPkId())) {
                // 修改的
                generalOutB.setPkCreator(generalOutbExtMap.get(generalOutB.getPkId()).getPkCreator());
                updateGeneralItems.add(generalOutB);
                saveScmItemSpecsList.addAll(generalOutB.getScmItemSpecsList());
                generalOutbExtMap.remove(generalOutB.getPkId());
            } else {
                // 新增的
                generalOutB.setPkGeneral(generalOutExt.getPkId());
                insertGeneralItems.add(generalOutB);
            }
        }
        String generalLockKey = CacheConstants.IC_GENERAL_OUT_LOCK + generalOutExt.getPkId();
        try {
            if (!redisService.lockKeyOnce(generalLockKey)) {
                throw new RuntimeException(ScmMsgConstants.BILL_NOT_OPERATION);
            }
            if (insertGeneralItems.size() > 0) {
                // 保存订单明细 新增的
                generalOutBiService.saveBatch(insertGeneralItems);
                List<ScmItemSpecs> scmItemSpecsList = scmItemSpecsService.packageOrderItemsSpecs(insertGeneralItems, generalOutExt.getPkId());
                if (scmItemSpecsList.size() > 0) {
                    saveScmItemSpecsList.addAll(scmItemSpecsList);
                }
            }
            if (updateGeneralItems.size() > 0) {
                // 修改订单明细 修改的
                updateGeneralItems.forEach(updateItems ->
                        generalOutBiService.updateById(updateItems));

            }
            if (generalOutbExtMap.size() > 0) {
                // 删除订单明细 删除的
                List<IcGeneralOutB> delGeneralItems = new ArrayList<>();
                generalOutbExtMap.forEach((key, value) -> delGeneralItems.add(value));
                generalOutBiService.deleteGeneralItemsByList(delGeneralItems, pkMember);
            }
            // 保存订单明细规格
            if (saveScmItemSpecsList.size() > 0) {
                scmItemSpecsService.saveBatch(saveScmItemSpecsList);
            }
            // 更新订单表
            updateById(generalOutExt);
        } finally {
            redisService.unlock(generalLockKey);
        }
    }

    @Override
    public IcGeneralOutHExt queryGeneralOutById(Long pkId, Integer orderStatus) {
        return baseMapper.queryGeneralInById(pkId, orderStatus);
    }

    @Override
    public IcGeneralOutHExt queryDisGeneralOutExtById(Long pkId, Integer orderStatus) {
        GeneralParam generalParam = new GeneralParam();
        generalParam.setPkId(pkId);
        generalParam.setOrderStatus(orderStatus);
        List<IcGeneralOutHExt> generalExtList = baseMapper.queryDisGeneralOutExtByCondition(generalParam);
        if(CollectionUtil.isNotEmpty(generalExtList)){
            return generalExtList.get(0);
        }
        return null;
    }

    @Override
    public List<IcGeneralOutHExt> queryDisGeneralOutExtCondition(GeneralParam generalParam) {
        if (generalParam.getEndDate() != null) {
            generalParam.setEndDate(DateUtils.afterDate(1, ChronoUnit.DAYS, generalParam.getEndDate()));
        }
        return baseMapper.queryDisGeneralOutExtByCondition(generalParam);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteGeneralOut(Long pkId, Long pkMember) {
        String generalOutLock = CacheConstants.IC_GENERAL_OUT_LOCK + pkId;
        if (!redisService.lockKeyOnce(generalOutLock)) {
            throw new RuntimeException(ScmMsgConstants.BILL_NOT_OPERATION);
        }
        // 删除规格明细表
        scmItemSpecsService.deleteItemSpecsById(EScmOrderType.GENERAL_OUT.getValue(), pkId, pkMember);
        generalOutBiService.deleteGeneralItemsByPkGeneral(pkId, pkMember);
        UpdateWrapper<IcGeneralOutH> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set(SystemFieldConstants.DEL_FLAG, EYesNo.NO.getIntValue());
        updateWrapper.set(SystemFieldConstants.PK_MODIFIED, pkMember);
        updateWrapper.set(SystemFieldConstants.MODIFIED_TIME, DateUtils.currentDateTime());
        updateWrapper.eq(SystemFieldConstants.PK_ID, pkId);
        update(updateWrapper);
        redisService.unlock(generalOutLock);
    }

    /*
     * @description: 将采购订单的参数转换为能保存的订单
     * @author: sui q
     * @date: 2023/11/20 15:53
     * @param: null null
     **/
    private void saveGeneralByParam(GeneralParam generalParam, Long pkMember) {
        IcGeneralOutH icGeneralOutH = BeanUtil.copyProperties(generalParam, IcGeneralOutH.class);
        List<IcGeneralOutB> generalItemList = getGeneralItems(generalParam, pkMember, icGeneralOutH);
        // 生成单据号
        icGeneralOutH.setOrderCode(scmBillNoService.createScmBillNoByOrderType(EScmOrderType.GENERAL_OUT.getValue()));
        // 保存主表
        save(icGeneralOutH);
        for (IcGeneralOutB generalOutB : generalItemList) {
            generalOutB.setPkGeneral(icGeneralOutH.getPkId());
        }
        // 保存子表
        generalOutBiService.saveBatch(generalItemList);
        List<ScmItemSpecs> saveScmItemSpecsList = scmItemSpecsService.packageOrderItemsSpecs(generalItemList, icGeneralOutH.getPkId());
        if (saveScmItemSpecsList.size() > 0) {
            scmItemSpecsService.saveBatch(saveScmItemSpecsList);
        }
    }

    private List<IcGeneralOutB> getGeneralItems(GeneralParam generalParam, Long pkMember, IcGeneralOutH icGeneralOutH) {
        // 根据国家获得汇率
        CurrencyDTO currencyDTO = currencyServiceApi.getCurrency(generalParam.getPkCountry()).getData();
        SysUser sysUser = userServiceApi.selectUserById(pkMember).getData();
        // 根据登录账号获得部门
        icGeneralOutH.setPkDept(sysUser.getPkDept().intValue());
        icGeneralOutH.setPkWhsmanager(pkMember);
        icGeneralOutH.setOrderType(EScmOrderType.GENERAL_OUT.getValue());
        // 计算累计数量 累计价税合计
        // 总数量
        BigDecimal totalNum = BigDecimal.ZERO;
        List<IcGeneralOutB> generalOutbList = new ArrayList<>();
        Date date = DateUtils.currentDateTime();
        for (GeneralBParam generalbParam : generalParam.getGeneralbParamList()) {
            IcGeneralOutB generalOutB = BeanUtil.copyProperties(generalbParam, IcGeneralOutB.class);
            // 金额
            generalOutB.setNcostmny(ComputeUtil.computeMultiply(generalOutB.getNcostprice(), generalOutB.getNnum()));
            generalOutB.setPkRate(currencyDTO.getPkId());
            totalNum = ComputeUtil.computeAdd(totalNum, generalOutB.getNnum());
            List<ItemSpecsParam> itemSpecsParamList = generalbParam.getScmItemSpecsList();
            scmItemSpecsService.packageScmItemByParam(itemSpecsParamList, generalOutB, generalParam.getPkCountry(), pkMember,
                    icGeneralOutH.getPkId(), generalOutB.getPkId(), EScmOrderType.GENERAL_OUT.getValue());
            generalOutbList.add(generalOutB);
        }
        icGeneralOutH.setPkCountry(generalParam.getPkCountry());
        if (generalParam.getPkId() == null) {
            icGeneralOutH.setPkCreator(pkMember);
        } else {
            icGeneralOutH.setPkModified(pkMember);
            icGeneralOutH.setModifiedTime(date);
        }
        icGeneralOutH.setTotalNum(totalNum);
        return generalOutbList;
    }

    private String approveGeneralByStatus(ApprovalBusinessResultDTO approvalBusinessResultDTO, Integer scmOrderStatus, Integer approveStatus){
        // 查询订单日志表
        List<ScmOrderApproveLog> scmOrderApproveLogList = scmOrderApproveLogService.queryScmOrderApproveLogByCondition(null, approvalBusinessResultDTO.getEApprovalBusiness().getValue(), approvalBusinessResultDTO.getBusinessCode());
        if (scmOrderApproveLogList == null || scmOrderApproveLogList.size() == 0) {
            return TransactionUtils.getContent(DocumentMsgConstants.DOCUMENT_NOT_EXISTS);
        }
        ScmOrderApproveLog scmOrderApproveLog = scmOrderApproveLogList.get(0);
        // 查询采购入库
        IcGeneralOutHExt generalOutExt = queryGeneralOutById(scmOrderApproveLog.getPkOrder(), EScmOrderStatus.SUBMIT.getValue());
        if (generalOutExt == null) {
            return TransactionUtils.getContent(DocumentMsgConstants.DOCUMENT_HAS_HANDLE);
        }
        // 更新采购入库单状态
        updateGeneralStatus(generalOutExt.getPkId(), approvalBusinessResultDTO.getLoginUser(), scmOrderStatus);
        // 更新前程日志表状态
        scmOrderApproveLogService.updateScmOrderApproveStatus(scmOrderApproveLog.getPkId(), approvalBusinessResultDTO.getLoginUser().getUserId(), approveStatus);
        // 弃审的时候回退批次数量
        if(EAgentApprovalStatus.REFUSE.getValue() == approveStatus){
            List<IcGeneralOutBExt> icGeneralOutbExtList = generalOutBiService.queryGeneralOutBiByList(EScmOrderType.GENERAL_OUT.getValue(), generalOutExt.getGeneralOutbExtList());
            if(icGeneralOutbExtList != null && icGeneralOutbExtList.size() >0){
                generalOutExt.setGeneralOutbExtList(icGeneralOutbExtList);
            }
            onHandNumService.backIcOnHandNumByGeneralOut(generalOutExt, generalOutExt.getGeneralOutbExtList(), EScmOrderType.GENERAL_OUT.getValue(), approvalBusinessResultDTO.getLoginUser().getUserId());
        }
        return null;
    }

    private void updateGeneralStatus(Long pkId, LoginUser loginUser, Integer orderStatus) {
        UpdateWrapper<IcGeneralOutH> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set(SaOrderFieldConstants.ORDER_STATUS, orderStatus);
        updateWrapper.set(SystemFieldConstants.PK_MODIFIED, loginUser.getUserId());
        updateWrapper.set(SystemFieldConstants.MODIFIED_TIME, DateUtils.currentDateTime());
        updateWrapper.eq(SystemFieldConstants.PK_ID, pkId);
        update(updateWrapper);
    }
}
