package com.hzs.scm.inventory.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.DateUtils;
import com.hzs.common.domain.scm.inventory.IcInventoryB;
import com.hzs.common.domain.scm.inventory.IcInventoryH;
import com.hzs.common.domain.scm.inventory.ext.IcInventoryBExt;
import com.hzs.common.domain.scm.inventory.ext.IcInventoryHExt;
import com.hzs.common.domain.scm.pub.ScmItemSpecs;
import com.hzs.common.domain.scm.pub.ScmOrderApproveLog;
import com.hzs.common.core.utils.TransactionUtils;
import com.hzs.scm.ic.service.IIcOnHandNumService;
import com.hzs.scm.inventory.mapper.IcInventoryHMapper;
import com.hzs.scm.inventory.param.InventoryBParam;
import com.hzs.scm.inventory.param.InventoryParam;
import com.hzs.scm.inventory.service.IIcInventoryBService;
import com.hzs.scm.inventory.service.IIcInventoryHService;
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.sys.dto.ApprovalBusinessResultDTO;
import com.hzs.system.sys.dto.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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-12-20
 */
@Service
public class IcInventoryHServiceImpl extends ServiceImpl<IcInventoryHMapper, IcInventoryH> implements IIcInventoryHService {

    @Autowired
    private IScmItemSpecsService scmItemSpecsService;

    @Autowired
    private IScmBillNoService scmBillNoService;

    @Autowired
    private IScmOrderApproveLogService scmOrderApproveLogService;

    @Autowired
    private IIcInventoryBService inventoryBiService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IIcOnHandNumService onHandNumService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertInventoryByInventoryParam(InventoryParam inventoryParam, Long pkMember) {
        saveInventoryByParam(inventoryParam, pkMember);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateInventoryByInventoryParam(IcInventoryHExt inventoryExt, InventoryParam inventoryParam, Long pkMember) {
        // 更新规格明细表，先删除在新增 根据主表主键删除
        scmItemSpecsService.deleteItemSpecsById(EScmOrderType.INVENTORY_ORDER.getValue(), inventoryExt.getPkId(), pkMember);
        inventoryExt.setOrderDate(inventoryParam.getOrderDate());
        inventoryExt.setInvType(inventoryParam.getInvType());
        inventoryExt.setRemark(inventoryParam.getRemark());
        inventoryExt.setPkWarehouse(inventoryParam.getPkWarehouse());
        inventoryExt.setPkAdjustor(inventoryParam.getPkAdjustor());
        inventoryExt.setPkWhsmanager(inventoryParam.getPkWhsmanager());
        inventoryExt.setPkCorp(inventoryParam.getPkCorp());
        // 更新订单明细表 分为3部分 删除的 新增的 修改的
        List<IcInventoryB> inventoryBiList = getInventoryB(inventoryParam, pkMember, inventoryExt);
        // 重新处理订单明细，将订单明细分为 删除的、新增的、修改的
        List<IcInventoryBExt> inventoryBiExtList = inventoryExt.getInventoryBiExtList();
        // 剩余的就是需要删除的
        Map<Long, IcInventoryBExt> inventoryBiExtMap = inventoryBiExtList.stream().collect(Collectors.toMap(IcInventoryBExt::getPkId, inventoryB->inventoryB));
        List<IcInventoryB> insertIcInventoryB = new ArrayList<>();
        List<IcInventoryB> updateIcInventoryB = new ArrayList<>();
        List<ScmItemSpecs> saveScmItemSpecsList = new ArrayList<>();
        for (IcInventoryB icInventoryB : inventoryBiList) {
            if (icInventoryB.getPkId() != null && inventoryBiExtMap.containsKey(icInventoryB.getPkId())) {
                // 修改的
                icInventoryB.setPkCreator(inventoryBiExtMap.get(icInventoryB.getPkId()).getPkCreator());
                updateIcInventoryB.add(icInventoryB);
                saveScmItemSpecsList.addAll(icInventoryB.getScmItemSpecsList());
                inventoryBiExtMap.remove(icInventoryB.getPkId());
            } else {
                // 新增的
                icInventoryB.setPkInventory(inventoryExt.getPkId());
                insertIcInventoryB.add(icInventoryB);
            }
        }
        String inventoryLockKey = CacheConstants.INVENTORY_ORDER_LOCK + inventoryExt.getPkId();
        try {
            if (!redisService.lockKeyOnce(inventoryLockKey)) {
                throw new RuntimeException(ScmMsgConstants.BILL_NOT_OPERATION);
            }
            if (insertIcInventoryB.size() > 0) {
                // 保存订单明细 新增的
                inventoryBiService.saveBatch(insertIcInventoryB);
                List<ScmItemSpecs> scmItemSpecsList = scmItemSpecsService.packageOrderItemsSpecs(insertIcInventoryB, inventoryExt.getPkId());
                if (scmItemSpecsList.size() > 0) {
                    saveScmItemSpecsList.addAll(scmItemSpecsList);
                }
            }
            if (updateIcInventoryB.size() > 0) {
                // 修改订单明细 修改的
                updateIcInventoryB.forEach(updateItems ->
                        inventoryBiService.updateById(updateItems));

            }
            if (inventoryBiExtMap.size() > 0) {
                // 删除订单明细 删除的
                List<IcInventoryB> delIcInventoryB = new ArrayList<>();
                inventoryBiExtMap.forEach((key, value) -> delIcInventoryB.add(value));
                inventoryBiService.deleteInventoryBiByList(delIcInventoryB, pkMember);
            }
            // 保存订单明细规格
            if (saveScmItemSpecsList.size() > 0) {
                scmItemSpecsService.saveBatch(saveScmItemSpecsList);
            }
            // 更新订单表
            updateById(inventoryExt);
        } finally {
            redisService.unlock(inventoryLockKey);
        }
    }

    @Override
    public IcInventoryHExt queryInventoryById(Long pkId, Integer orderStatus) {
        return baseMapper.queryIcInventoryById(pkId, orderStatus);
    }

    @Override
    public IcInventoryHExt queryDisInventoryExtById(Long pkId, Integer orderStatus) {
        InventoryParam inventoryParam = new InventoryParam();
        inventoryParam.setPkId(pkId);
        inventoryParam.setOrderStatus(orderStatus);
        List<IcInventoryHExt> inventoryExtList = baseMapper.queryDisIcInventoryExtByCondition(inventoryParam);
        if(CollectionUtil.isNotEmpty(inventoryExtList)){
            return inventoryExtList.get(0);
        }
        return null;
    }

    @Override
    public List<IcInventoryHExt> queryDisInventoryExtByCondition(InventoryParam inventoryParam) {
        if (inventoryParam.getEndDate() != null) {
            inventoryParam.setEndDate(DateUtils.afterDate(1, ChronoUnit.DAYS, inventoryParam.getEndDate()));
        }
        return baseMapper.queryDisIcInventoryExtByCondition(inventoryParam);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteInventory(Long pkId, Long pkMember) {
        String inventoryLock = CacheConstants.INVENTORY_ORDER_LOCK + pkId;
        if (!redisService.lockKeyOnce(inventoryLock)) {
            throw new RuntimeException(ScmMsgConstants.BILL_NOT_OPERATION);
        }
        // 删除规格明细表
        scmItemSpecsService.deleteItemSpecsById(EScmOrderType.INVENTORY_ORDER.getValue(), pkId, pkMember);
        inventoryBiService.deleteInventoryBiByPkInventory(pkId, pkMember);
        UpdateWrapper<IcInventoryH> 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(inventoryLock);
    }

    /*
     * @description: 将采购订单的参数转换为能保存的订单
     * @author: sui q
     * @date: 2023/11/20 15:53
     * @param: null null
     **/
    private void saveInventoryByParam(InventoryParam inventoryParam, Long pkMember) {
        IcInventoryH inventoryH = BeanUtil.copyProperties(inventoryParam, IcInventoryH.class);
        List<IcInventoryB> inventoryBiList = getInventoryB(inventoryParam, pkMember, inventoryH);
        // 生成单据号
        inventoryH.setOrderCode(scmBillNoService.createScmBillNoByOrderType(EScmOrderType.INVENTORY_ORDER.getValue()));
        // 保存主表
        save(inventoryH);
        for (IcInventoryB icInventoryB : inventoryBiList) {
            icInventoryB.setPkInventory(inventoryH.getPkId());
        }
        // 保存子表
        inventoryBiService.saveBatch(inventoryBiList);
        List<ScmItemSpecs> saveScmItemSpecsList = scmItemSpecsService.packageOrderItemsSpecs(inventoryBiList, inventoryH.getPkId());
        if (saveScmItemSpecsList.size() > 0) {
            scmItemSpecsService.saveBatch(saveScmItemSpecsList);
        }
    }

    private List<IcInventoryB> getInventoryB(InventoryParam inventoryParam, Long pkMember, IcInventoryH inventoryH) {
        inventoryH.setPkDept(inventoryParam.getPkDept());
        List<IcInventoryB> inventoryBiList = new ArrayList<>();
        Date date = DateUtils.currentDateTime();
        for (InventoryBParam inventoryBiParam : inventoryParam.getInventoryBiParamList()) {
            IcInventoryB icInventoryB = BeanUtil.copyProperties(inventoryBiParam, IcInventoryB.class);
            icInventoryB.setPkOnhandnum(inventoryBiParam.getPkOnhandnum());
            // 金额
            List<ItemSpecsParam> itemSpecsParamList = inventoryBiParam.getScmItemSpecsList();
            scmItemSpecsService.packageScmItemByParam(itemSpecsParamList, icInventoryB, inventoryParam.getPkCountry(), pkMember,
                    inventoryH.getPkId(), icInventoryB.getPkId(), EScmOrderType.INVENTORY_ORDER.getValue());
            inventoryBiList.add(icInventoryB);
        }
        inventoryH.setPkCountry(inventoryParam.getPkCountry());
        if (inventoryParam.getPkId() == null) {
            inventoryH.setPkCreator(pkMember);
        } else {
            inventoryH.setPkModified(pkMember);
            inventoryH.setModifiedTime(date);
        }
        return inventoryBiList;
    }

    private void updateInventoryStatus(Long pkId, LoginUser loginUser, Integer orderStatus) {
        UpdateWrapper<IcInventoryH> 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);
    }

    private String approveInventoryByStatus(ApprovalBusinessResultDTO approvalBusinessResultDTO, Integer scmOrderStatus, Integer approveStatus){
        try {
            // 查询订单日志表
            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);
            // 查询库存盘点单
            IcInventoryHExt inventoryExt = queryDisInventoryExtById(scmOrderApproveLog.getPkOrder(), EScmOrderStatus.SUBMIT.getValue());
            if (inventoryExt == null) {
                return TransactionUtils.getContent(DocumentMsgConstants.DOCUMENT_HAS_HANDLE);
            }
            // 更新库存盘点单状态
            updateInventoryStatus(inventoryExt.getPkId(), approvalBusinessResultDTO.getLoginUser(), scmOrderStatus);
            // 更新前程日志表状态
            scmOrderApproveLogService.updateScmOrderApproveStatus(scmOrderApproveLog.getPkId(), approvalBusinessResultDTO.getLoginUser().getUserId(), approveStatus);
            if (EInventoryType.INVENTORY_IN.getValue() == inventoryExt.getInvType()) {
                // 盘盈审核通过更新现存量
                if (EAgentApprovalStatus.APPROVED.getValue() == approveStatus) {
                    // 查询库存盘点单明细表
                    packageInventoryBiList(inventoryExt);
                    // 转换封装数据，将数据更新成可以入库的数据
                    // 更新现存量 // 更新采购订单累计入库数量
                    onHandNumService.mergeIcOnHandNumByGeneralIn(inventoryExt, inventoryExt.getInventoryBiExtList(), EScmOrderType.INVENTORY_ORDER.getValue(), approvalBusinessResultDTO.getLoginUser().getUserId());
                }
            } else {
                // 盘亏驳回退回数量
                // 弃审的时候回退批次数量
                if (EAgentApprovalStatus.REFUSE.getValue() == approveStatus) {
                    packageInventoryBiList(inventoryExt);
                    onHandNumService.backIcOnHandNumByGeneralOut(inventoryExt, inventoryExt.getInventoryBiExtList(), EScmOrderType.INVENTORY_ORDER.getValue(), approvalBusinessResultDTO.getLoginUser().getUserId());
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return null;
    }

    private void packageInventoryBiList(IcInventoryHExt inventoryExt) {
        List<IcInventoryBExt> inventoryBiExtList = inventoryBiService.queryInventoryBiByPk(EScmOrderType.INVENTORY_ORDER.getValue(), inventoryExt.getInventoryBiExtList());
        if (inventoryBiExtList != null && inventoryBiExtList.size() > 0) {
            for (IcInventoryBExt inventoryBiExt : inventoryBiExtList) {
                inventoryBiExt.setPkStorehouse(inventoryExt.getPkWarehouse());
                inventoryBiExt.setNnum(inventoryBiExt.getNdiffastnum());
            }
            inventoryExt.setInventoryBiExtList(inventoryBiExtList);
        }
    }
}
