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.ErpMaterialCheckInfoVo;
import com.maintain.business.domain.vo.ErpMaterialInventoryRecordVo;
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.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static net.sf.jsqlparser.parser.feature.Feature.update;

/**
 * 物资盘点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;
    private final ErpMaterialInventoryRecordMapper materialInventoryRecordMapper;

    /**
     * 查询物资盘点
     */
    @Override
    public ErpMaterialCheckVo queryById(Long id){
        ErpMaterialCheckVo checkVo = baseMapper.selectVoById(id);
        LambdaQueryWrapper<ErpMaterialCheckInfo> lqw = Wrappers.lambdaQuery();
        lqw.eq(ErpMaterialCheckInfo::getCheckId, id);
        List<ErpMaterialCheckInfoVo> checkInfoVoList = checkInfoMapper.selectVoList(lqw);
        checkVo.setCheckInfoList(checkInfoVoList);
        List<ErpMaterialCheckInfoVo> checkInfoJustList = new ArrayList<>();
        List<ErpMaterialCheckInfoVo> checkInfoLoseList = new ArrayList<>();
        for (ErpMaterialCheckInfoVo infoVo : checkInfoVoList) {
            if (infoVo.getResultState() == 1) {
                checkInfoJustList.add(infoVo);
            }else if (infoVo.getResultState() == 2) {
                checkInfoLoseList.add(infoVo);
            }
        }
        checkVo.setCheckInfoJustList(checkInfoJustList);
        checkVo.setCheckInfoLoseList(checkInfoLoseList);
        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) {
        List<SysDept> sysDeptList = deptMapper.selectChildrenDeptById(LoginHelper.getDeptId(), null);
        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.in(!sysDeptList.isEmpty(), ErpMaterialCheck::getDeptId, sysDeptList.stream().map(SysDept::getDeptId).collect(Collectors.toList()));
        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;
    }

    /**
     * 修改物资盘点
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateByBo(ErpMaterialCheckBo bo) {
        ErpMaterialCheck materialCheck = baseMapper.selectById(bo.getId());
        materialCheck.setTaskName(bo.getTaskName());
        materialCheck.setTaskStartTime(bo.getTaskStartTime());
        materialCheck.setRemark(bo.getRemark());
        if (!bo.getDeptId().equals(materialCheck.getDeptId())) {
            /* 车间变更 */
            SysDept sysDept = deptMapper.selectVoById(bo.getDeptId());
            materialCheck.setDeptId(sysDept.getDeptId());
            materialCheck.setDeptName(sysDept.getDeptName());
            /* 仓库变更 */
            ErpWarehouse warehouse = warehouseMapper.selectById(bo.getWarehouseId());
            materialCheck.setWarehouseId(warehouse.getId());
            materialCheck.setWarehouseName(warehouse.getName());
            /* 仓库盘点状态变更 */
            warehouse.setIsCheck(IsEnableStatus.YES.getCode());
            warehouseMapper.updateById(warehouse);
            /* 原仓库状态变更 */
            ErpWarehouse erpWarehouse = new ErpWarehouse();
            erpWarehouse.setId(materialCheck.getWarehouseId());
            erpWarehouse.setIsCheck(IsEnableStatus.NO.getCode());
        }
        /* 盘点人存在变更 */
        if (!bo.getTaskUserId().equals(materialCheck.getTaskUserId())) {
            SysUser sysUser = userMapper.selectVoById(bo.getTaskUserId());
            materialCheck.setTaskUserId(sysUser.getUserId());
            materialCheck.setTaskUserName(sysUser.getNickName());
        }
        boolean flag = baseMapper.updateById(materialCheck) > 0;
        if (flag) {
            /* 删除旧绑定 */
            LambdaQueryWrapper<ErpMaterialCheckInfo> lambdaQuery = Wrappers.lambdaQuery();
            lambdaQuery.eq(ErpMaterialCheckInfo::getCheckId, bo.getId());
            checkInfoMapper.delete(lambdaQuery);
            /* 创建新绑定 */
            checkInfoMapper.insertBatch(bo.getCheckInfoList().stream().map(item -> {
                ErpMaterialCheckInfo checkInfo = BeanUtil.toBean(item, ErpMaterialCheckInfo.class);
                checkInfo.setId(null);
                checkInfo.setCheckId(bo.getId());
                return checkInfo;
            }).collect(Collectors.toList()));
        }
        return flag;
    }

    /**
     * 物资盘点
     *
     * @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 = warehouseMapper.selectById(materialCheck.getWarehouseId());
        warehouse.setIsCheck(IsEnableStatus.NO.getCode());
        warehouseMapper.updateById(warehouse);
        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());
                /* 查询物料库存 */
                ErpMaterialInventoryRecordVo recordVo = materialInventoryRecordMapper.queryMaterialByWarehouseIdAndMaterialId(bo.getWarehouseId(), item.getVendorId(), item.getMaterialId());
                /* 如果recordVo为空，说明改物料没有过库存变动记录数据，默认给0 */
                BigDecimal inventory = new BigDecimal("0");
                if (null != recordVo) {
                    inventory = recordVo.getInventory();
                }
                // 判断盘盈或盘亏 盘盈则新增入库、盘亏新增出库
                if (item.getResultState().equals(CheckInfoState.ONE.getCode())) {
                    ErpMaterialPutawayInfo putawayInfo = BeanUtil.toBean(material, ErpMaterialPutawayInfo.class);
                    putawayInfo.setPutawayNumber(item.getCheckNum().subtract(inventory));
                    putawayInfo.setMaterialId(item.getMaterialId());
                    putawayInfo.setVendorId(item.getVendorId());
                    putawayInfo.setId(null);
                    putawayInfoList.add(putawayInfo);
                }else if (item.getResultState().equals(CheckInfoState.TWO.getCode())) {
                    ErpMaterialPickingInfo pickingInfo = BeanUtil.toBean(material, ErpMaterialPickingInfo.class);
                    pickingInfo.setCollectNumber(inventory.subtract(item.getCheckNum()));
                    pickingInfo.setMaterialId(item.getMaterialId());
                    pickingInfo.setVendorId(item.getVendorId());
                    pickingInfo.setId(null);
                    pickingInfoList.add(pickingInfo);
                }
            });
            /* 创建入库单 */
            if (!putawayInfoList.isEmpty()) {
                ErpMaterialPutaway putaway = new ErpMaterialPutaway();
                putaway.setPutawayCode(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());
                putaway.setCreateDeptId(LoginHelper.getDeptId());
                materialPutawayMapper.insert(putaway);
                materialPutawayInfoMapper.insertBatch(
                    putawayInfoList
                        .stream()
                        .peek(item -> item.setPutawayId(putaway.getId()))
                        .collect(Collectors.toList()));
                /* 新增物料库存记录 */
                materialInventoryRecordMapper.insertBatch(
                    putawayInfoList.stream().map(item -> {
                        ErpMaterialInventoryRecord record = new ErpMaterialInventoryRecord();
                        record.setInfoId(item.getId());
                        record.setMaterialId(item.getMaterialId());
                        record.setWarehouseId(warehouse.getId());
                        record.setVendorId(item.getVendorId());
                        record.setDeptId(warehouse.getDeptId());
                        record.setNumber(item.getPutawayNumber());
                        record.setPrice(item.getPutawayPrice());
                        record.setMoney(item.getPutawayMoney());
                        record.setType(InventoryType.putaway.getCode());
                        return record;
                    }).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.setCreateDeptId(LoginHelper.getDeptId());
                materialPickingMapper.insert(picking);
                materialPickingInfoMapper.insertBatch(
                    pickingInfoList
                        .stream()
                        .peek(item -> item.setPickingId(picking.getId()))
                        .collect(Collectors.toList()));
                /* 新增物料库存记录 */
                materialInventoryRecordMapper.insertBatch(
                    pickingInfoList.stream().map(item -> {
                        ErpMaterialInventoryRecord record = new ErpMaterialInventoryRecord();
                        record.setInfoId(item.getId());
                        record.setMaterialId(item.getMaterialId());
                        record.setWarehouseId(warehouse.getId());
                        record.setVendorId(item.getVendorId());
                        record.setDeptId(warehouse.getDeptId());
                        record.setNumber(item.getCollectNumber());
                        record.setPrice(item.getPrice());
                        record.setMoney(item.getMoney());
                        record.setType(InventoryType.picking.getCode());
                        return record;
                    }).collect(Collectors.toList())
                );
            }
        }
        return flag;
    }

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

    /**
     * 批量删除物资盘点
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        /* 删除盘点明细 */
        LambdaQueryWrapper<ErpMaterialCheckInfo> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.in(ErpMaterialCheckInfo::getCheckId, ids);
        checkInfoMapper.delete(lambdaQueryWrapper);
        /* 仓库盘点状态变更 */
        List<ErpMaterialCheckVo> checkVoList = baseMapper.selectVoBatchIds(ids);
        List<Long> collect = checkVoList.stream().map(ErpMaterialCheckVo::getWarehouseId).collect(Collectors.toList());
        if (!collect.isEmpty()) {
            LambdaUpdateWrapper<ErpWarehouse> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.in(ErpWarehouse::getId, collect).set(ErpWarehouse::getIsCheck, CheckInfoState.ONE.getCode());
            warehouseMapper.update(updateWrapper);
        }
        /* 删除盘点单 */
        return baseMapper.deleteBatchIds(ids) > 0;
    }
}
