package com.maintain.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.maintain.business.domain.*;
import com.maintain.business.domain.bo.ErpMaterialCheckInfoBo;
import com.maintain.business.domain.vo.ErpWarehouseVo;
import com.maintain.business.mapper.*;
import com.maintain.business.service.IErpMaterialService;
import com.maintain.common.core.domain.BaseEntity;
import com.maintain.common.core.domain.entity.SysDept;
import com.maintain.common.core.domain.entity.SysUser;
import com.maintain.common.enums.*;
import com.maintain.common.helper.LoginHelper;
import com.maintain.common.utils.StringUtils;
import com.maintain.common.core.page.TableDataInfo;
import com.maintain.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.maintain.common.utils.redis.RedisUtils;
import com.maintain.system.mapper.SysDeptMapper;
import com.maintain.system.mapper.SysUserMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.maintain.business.domain.bo.ErpMaterialCheckBo;
import com.maintain.business.domain.vo.ErpMaterialCheckVo;
import com.maintain.business.service.IErpMaterialCheckService;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 物资盘点Service业务层处理
 *
 * @author liushuai
 * @date 2025-04-03
 */
@RequiredArgsConstructor
@Service
public class ErpMaterialCheckServiceImpl implements IErpMaterialCheckService {

    private final ErpMaterialCheckMapper baseMapper;
    private final SysDeptMapper deptMapper;
    private final ErpWarehouseMapper warehouseMapper;
    private final SysUserMapper userMapper;
    private final ErpMaterialCheckInfoMapper checkInfoMapper;
    private final ErpMaterialMapper materialMapper;
    private final IErpMaterialService materialService;
    private final ErpMaterialPutawayMapper materialPutawayMapper;
    private final ErpMaterialPutawayInfoMapper materialPutawayInfoMapper;
    private final ErpMaterialPickingMapper materialPickingMapper;
    private final ErpMaterialPickingInfoMapper materialPickingInfoMapper;
    /**
     * 查询物资盘点
     */
    @Override
    public ErpMaterialCheckVo queryById(Long id){
        ErpMaterialCheckVo checkVo = baseMapper.selectVoById(id);
        LambdaQueryWrapper<ErpMaterialCheckInfo> lqw = Wrappers.lambdaQuery();
        lqw.eq(ErpMaterialCheckInfo::getCheckId, id);
        checkVo.setCheckInfoList(checkInfoMapper.selectVoList(lqw));
        return checkVo;
    }

    /**
     * 查询物资盘点列表
     */
    @Override
    public TableDataInfo<ErpMaterialCheckVo> queryPageList(ErpMaterialCheckBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ErpMaterialCheck> lqw = buildQueryWrapper(bo);
        Page<ErpMaterialCheckVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询物资盘点列表
     */
    @Override
    public List<ErpMaterialCheckVo> queryList(ErpMaterialCheckBo bo) {
        LambdaQueryWrapper<ErpMaterialCheck> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<ErpMaterialCheck> buildQueryWrapper(ErpMaterialCheckBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ErpMaterialCheck> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getTaskCode()), ErpMaterialCheck::getTaskCode, bo.getTaskCode());
        lqw.like(StringUtils.isNotBlank(bo.getTaskName()), ErpMaterialCheck::getTaskName, bo.getTaskName());
        lqw.eq(bo.getTaskUserId() != null, ErpMaterialCheck::getTaskUserId, bo.getTaskUserId());
        lqw.like(StringUtils.isNotBlank(bo.getTaskUserName()), ErpMaterialCheck::getTaskUserName, bo.getTaskUserName());
        lqw.eq(bo.getTaskStartTime() != null, ErpMaterialCheck::getTaskStartTime, bo.getTaskStartTime());
        lqw.eq(bo.getTaskEndTime() != null, ErpMaterialCheck::getTaskEndTime, bo.getTaskEndTime());
        lqw.eq(bo.getWarehouseId() != null, ErpMaterialCheck::getWarehouseId, bo.getWarehouseId());
        lqw.like(StringUtils.isNotBlank(bo.getWarehouseName()), ErpMaterialCheck::getWarehouseName, bo.getWarehouseName());
        lqw.eq(bo.getCheckType() != null, ErpMaterialCheck::getCheckType, bo.getCheckType());
        lqw.eq(bo.getCheckState() != null, ErpMaterialCheck::getCheckState, bo.getCheckState());
        lqw.eq(bo.getDeptId() != null, ErpMaterialCheck::getDeptId, bo.getDeptId());
        lqw.like(StringUtils.isNotBlank(bo.getDeptName()), ErpMaterialCheck::getDeptName, bo.getDeptName());
        lqw.eq(bo.getCreateDeptId() != null, ErpMaterialCheck::getCreateDeptId, bo.getCreateDeptId());
        lqw.orderByDesc(ErpMaterialCheck::getCreateTime);
        return lqw;
    }

    /**
     * 新增物资盘点
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean insertByBo(ErpMaterialCheckBo bo) {
        ErpMaterialCheck add = BeanUtil.toBean(bo, ErpMaterialCheck.class);
        validEntityBeforeSave(add);
        add.setTaskCode(RedisUtils.generateNextNumber("PD"));
        SysDept sysDept = deptMapper.selectVoById(add.getDeptId());
        add.setDeptName(sysDept.getDeptName());
        ErpWarehouse warehouse = warehouseMapper.selectById(add.getWarehouseId());
        add.setWarehouseName(warehouse.getName());
        add.setTaskUserId(LoginHelper.getUserId());
        add.setTaskUserName(LoginHelper.getUsername());
        add.setCreateDeptId(LoginHelper.getDeptId());
        add.setCheckState(CheckState.ONE.getCode());
        // 将盘点的仓库状态改为 是
        warehouse.setIsCheck(IsEnableStatus.YES.getCode());
        warehouseMapper.updateById(warehouse);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            List<ErpMaterialCheckInfo> collect = bo.getCheckInfoList().stream().map(item -> {
                ErpMaterialCheckInfo checkInfo = BeanUtil.toBean(item, ErpMaterialCheckInfo.class);
                checkInfo.setId(null);
                checkInfo.setCheckId(add.getId());
                return checkInfo;
            }).collect(Collectors.toList());
            checkInfoMapper.insertBatch(collect);
            // 将盘点所在仓库下的物料是否盘点状态更改为 是
            LambdaUpdateWrapper<ErpMaterial> materialLambdaUpdateWrapper = Wrappers.lambdaUpdate();
            materialLambdaUpdateWrapper.eq(ErpMaterial::getWarehouseId, add.getWarehouseId());
            materialLambdaUpdateWrapper.set(ErpMaterial::getIsCheck, IsEnableStatus.YES.getCode());
            materialMapper.update(materialLambdaUpdateWrapper);
        }
        return flag;
    }

    /**
     * 修改物资盘点
     */
    @Override
    public Boolean updateByBo(ErpMaterialCheckBo bo) {
        ErpMaterialCheck update = BeanUtil.toBean(bo, ErpMaterialCheck.class);
        validEntityBeforeSave(update);
        SysDept sysDept = deptMapper.selectVoById(update.getDeptId());
        update.setDeptName(sysDept.getDeptName());
        ErpWarehouseVo warehouseVo = warehouseMapper.selectVoById(update.getWarehouseId());
        update.setWarehouseName(warehouseVo.getName());
        SysUser sysUser = userMapper.selectVoById(update.getTaskUserId());
        update.setTaskUserName(sysUser.getNickName());
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 物资盘点
     *
     * @param bo
     * @return boolean
     */
    @Override
    public Boolean check(ErpMaterialCheckBo bo) {
        // 更新盘点结束时间
        ErpMaterialCheck materialCheck = baseMapper.selectById(bo.getId());
        materialCheck.setTaskEndTime(new Date());
        materialCheck.setCheckState(CheckState.TWO.getCode());
        // 将盘点的仓库状态改为 否
        ErpWarehouse warehouse = new ErpWarehouse();
        warehouse.setId(bo.getWarehouseId());
        warehouse.setIsCheck(IsEnableStatus.NO.getCode());
        warehouseMapper.updateById(warehouse);
        // 将盘点所在仓库下的物料是否盘点状态更改为 是
        LambdaUpdateWrapper<ErpMaterial> materialLambdaUpdateWrapper = Wrappers.lambdaUpdate();
        materialLambdaUpdateWrapper.eq(ErpMaterial::getWarehouseId, materialCheck.getWarehouseId());
        materialLambdaUpdateWrapper.set(ErpMaterial::getIsCheck, IsEnableStatus.NO.getCode());
        materialMapper.update(materialLambdaUpdateWrapper);
        boolean flag = baseMapper.updateById(materialCheck) > 0;
        if (flag) {
            List<ErpMaterialPutawayInfo> putawayInfoList = new ArrayList<>();
            List<ErpMaterialPickingInfo> pickingInfoList = new ArrayList<>();
            LambdaQueryWrapper<ErpMaterialCheckInfo> infoLambdaQueryWrapper = Wrappers.lambdaQuery();
            infoLambdaQueryWrapper.eq(ErpMaterialCheckInfo::getCheckId, materialCheck.getId());
            List<ErpMaterialCheckInfo> checkInfoList = checkInfoMapper.selectList(infoLambdaQueryWrapper);
            if (checkInfoList.isEmpty()) {
                throw new RuntimeException("盘点结束失败，盘点明细不能为空！");
            }
            checkInfoList.forEach(item -> {
                ErpMaterial material = materialMapper.selectById(item.getMaterialId());
                // 判断盘盈或盘亏
                if (item.getResultState().equals(CheckInfoState.ONE.getCode())) {
                    ErpMaterialPutawayInfo putawayInfo = BeanUtil.toBean(material, ErpMaterialPutawayInfo.class);
                    putawayInfo.setPutawayNumber(item.getCheckNum().subtract(material.getInventory()));
                    putawayInfo.setMaterialId(material.getId());
                    putawayInfo.setId(null);
                    putawayInfoList.add(putawayInfo);
                }else if (item.getResultState().equals(CheckInfoState.TWO.getCode())) {
                    ErpMaterialPickingInfo pickingInfo = BeanUtil.toBean(material, ErpMaterialPickingInfo.class);
                    pickingInfo.setCollectNumber(material.getInventory().subtract(item.getCheckNum()));
                    pickingInfo.setMaterialId(material.getId());
                    pickingInfo.setId(null);
                    pickingInfoList.add(pickingInfo);
                }
                material.setInventory(item.getCheckNum());
                materialMapper.updateById(material);
            });
            if (!putawayInfoList.isEmpty()) {
                ErpMaterialPutaway putaway = new ErpMaterialPutaway();
                putaway.setPutawayNumber(RedisUtils.generateNextNumber("RK"));
                putaway.setPutawayType(PutawayType.TWO.getCode());
                putaway.setPutawayTime(new Date());
                putaway.setState(PutawayState.TWO.getCode());
                putaway.setWarehouseId(materialCheck.getWarehouseId());
                putaway.setWarehouseName(materialCheck.getWarehouseName());
                materialPutawayMapper.insert(putaway);
                materialPutawayInfoMapper.insertBatch(
                    putawayInfoList
                        .stream()
                        .peek(item -> item.setPutawayId(putaway.getId()))
                        .collect(Collectors.toList()));
            }
            if (!pickingInfoList.isEmpty()) {
                ErpMaterialPicking picking = new ErpMaterialPicking();
                picking.setOutNumber(RedisUtils.generateNextNumber("CK"));
                picking.setType(PickingType.TWO.getCode());
                picking.setState(PickingState.TWO.getCode());
                picking.setOutTime(new Date());
                // picking.setReceiveUserId(LoginHelper.getUserId());
                // picking.setReceiveUserName(LoginHelper.getUsername());
                materialPickingMapper.insert(picking);
                materialPickingInfoMapper.insertBatch(
                    pickingInfoList
                        .stream()
                        .peek(item -> item.setPickingId(picking.getId()))
                        .collect(Collectors.toList()));
            }
        }
        return flag;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ErpMaterialCheck entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除物资盘点
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }
}
