package com.maintain.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.maintain.business.domain.ErpMaterial;
import com.maintain.business.domain.bo.ErpMaterialBo;
import com.maintain.business.domain.vo.*;
import com.maintain.business.mapper.*;
import com.maintain.business.service.IErpMaterialService;
import com.maintain.common.core.domain.PageQuery;
import com.maintain.common.core.page.TableDataInfo;
import com.maintain.common.enums.IsDeleteStatus;
import com.maintain.common.enums.IsEnableStatus;
import com.maintain.common.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 物资Service业务层处理
 *
 * @author liushuai
 * @date 2025-04-03
 */
@RequiredArgsConstructor
@Service
public class ErpMaterialServiceImpl implements IErpMaterialService {

    private final ErpMaterialMapper baseMapper;
    private final ErpMaterialTypeMapper materialTypeMapper;
    private final ErpMaterialVendorMapper materialVendorMapper;
    private final ErpWarehouseLocationMapper warehouseLocationMapper;
    private final ErpWarehouseMapper warehouseMapper;

    /**
     * 查询物资
     */
    @Override
    public ErpMaterialVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

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

    /**
     * 查询物资列表(自定义查询)
     */
    @Override
    public TableDataInfo<ErpMaterialVo> customQueryPageList(ErpMaterialBo bo, PageQuery pageQuery) {
        QueryWrapper<ErpMaterial> query = Wrappers.query();
        query.like(null != bo.getVendorName(), "t.vendor_name", bo.getVendorName())
            .like(null != bo.getMaterialName(), "t.material_name", bo.getMaterialName())
            .like(null != bo.getMaterialCode(), "t.material_code", bo.getMaterialCode())
            .like(null != bo.getMaterialSpecifications(), "t.material_specifications", bo.getMaterialSpecifications())
            .like(null != bo.getWarehouseName(), "t.name", bo.getWarehouseName())
            .eq(null != bo.getWarehouseId(), "t.warehouse_id", bo.getWarehouseId())
            .in(null != bo.getWarehouseIdList(), "t.warehouse_id", bo.getWarehouseIdList())
            .ge(null != bo.getInventory(), "t.inventory", bo.getInventory());
        Page<ErpMaterialVo> result = baseMapper.customQueryPageList(pageQuery.build(), query);
        return TableDataInfo.build(result);
    }

    /**
     * 查询物资列表根据仓库ID(不分页)
     *
     * @param bo
     */
    @Override
    public List<ErpMaterialVo> customQueryListByWarehouseId(ErpMaterialBo bo) {
        return baseMapper.customQueryListByWarehouseId(bo.getWarehouseId());
    }

    /**
     * 查询物资列表(自定义查询全部)
     *
     * @param bo
     * @param pageQuery
     */
    @Override
    public TableDataInfo<ErpMaterialVo> customQueryPageListAll(ErpMaterialBo bo, PageQuery pageQuery) {
        QueryWrapper<ErpMaterial> query = Wrappers.query();
        query.eq("m.is_delete", IsDeleteStatus.NO.getCode())
            .like(bo.getMaterialCode() != null, "m.material_code", bo.getMaterialCode())
            .like(bo.getMaterialName() != null, "m.material_name", bo.getMaterialName())
            .like(bo.getMaterialSpecifications() != null, "m.material_specifications", bo.getMaterialSpecifications())
            .like(bo.getVendorName() != null, "vendor_name", bo.getVendorName());
        Page<ErpMaterialVo> result = baseMapper.customQueryPageListByWarehouseId(pageQuery.build(), query, bo.getWarehouseId());
        return TableDataInfo.build(result);
    }

    /**
     * 查询物资列表
     */
    @Override
    public List<ErpMaterialVo> queryList(ErpMaterialBo bo) {
        LambdaQueryWrapper<ErpMaterial> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private QueryWrapper<ErpMaterial> customBuildQueryWrapper(ErpMaterialBo bo) {
        QueryWrapper<ErpMaterial> query = Wrappers.query();
        query.like(null != bo.getVendorName(), "t.vendor_name", bo.getVendorName())
            .like(null != bo.getMaterialName(), "t.material_name", bo.getMaterialName())
            .like(null != bo.getMaterialCode(), "t.material_code", bo.getMaterialCode())
            .like(null != bo.getMaterialSpecifications(), "t.material_specifications", bo.getMaterialSpecifications())
            .like(null != bo.getWarehouseName(), "t.name", bo.getWarehouseName())
            .eq(null != bo.getWarehouseId(), "t.warehouse_id", bo.getWarehouseId())
            .in(null != bo.getWarehouseIdList(), "t.warehouse_id", bo.getWarehouseIdList())
            .ge(null != bo.getInventory(), "t.inventory", bo.getInventory());
        return query;
    }

    private LambdaQueryWrapper<ErpMaterial> buildQueryWrapper(ErpMaterialBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ErpMaterial> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getIsCheck() != null, ErpMaterial::getIsCheck, bo.getIsCheck());
        lqw.eq(bo.getDeptId() != null, ErpMaterial::getDeptId, bo.getDeptId());
        lqw.eq(bo.getWarehouseId() != null, ErpMaterial::getWarehouseId, bo.getWarehouseId());
        lqw.eq(bo.getMaterialTypeId() != null, ErpMaterial::getMaterialTypeId, bo.getMaterialTypeId());
        lqw.like(StringUtils.isNotBlank(bo.getMaterialTypeName()), ErpMaterial::getMaterialTypeName, bo.getMaterialTypeName());
        lqw.eq(bo.getWarehouseLocationId() != null, ErpMaterial::getWarehouseLocationId, bo.getWarehouseLocationId());
        lqw.eq(StringUtils.isNotBlank(bo.getWarehouseLocationType()), ErpMaterial::getWarehouseLocationType, bo.getWarehouseLocationType());
        lqw.eq(bo.getVendorId() != null, ErpMaterial::getVendorId, bo.getVendorId());
        lqw.like(StringUtils.isNotBlank(bo.getVendorName()), ErpMaterial::getVendorName, bo.getVendorName());
        lqw.like(StringUtils.isNotBlank(bo.getMaterialCode()), ErpMaterial::getMaterialCode, bo.getMaterialCode());
        lqw.like(StringUtils.isNotBlank(bo.getMaterialName()), ErpMaterial::getMaterialName, bo.getMaterialName());
        lqw.like(StringUtils.isNotBlank(bo.getMaterialSpecifications()), ErpMaterial::getMaterialSpecifications, bo.getMaterialSpecifications());
        lqw.eq(StringUtils.isNotBlank(bo.getMaterialUnit()), ErpMaterial::getMaterialUnit, bo.getMaterialUnit());
        lqw.eq(bo.getMaterialWarrantyPeriod() != null, ErpMaterial::getMaterialWarrantyPeriod, bo.getMaterialWarrantyPeriod());
        lqw.eq(bo.getReferencePrice() != null, ErpMaterial::getReferencePrice, bo.getReferencePrice());
        lqw.eq(bo.getSellingPrice() != null, ErpMaterial::getSellingPrice, bo.getSellingPrice());
        lqw.eq(bo.getInventory() != null, ErpMaterial::getInventory, bo.getInventory());
        lqw.eq(StringUtils.isNotBlank(bo.getIsEnable()), ErpMaterial::getIsEnable, bo.getIsEnable());
        lqw.eq(StringUtils.isNotBlank(bo.getIsUniversal()), ErpMaterial::getIsUniversal, bo.getIsUniversal());
        lqw.eq(ErpMaterial::getIsDelete, IsDeleteStatus.NO.getCode());
        lqw.orderByDesc(ErpMaterial::getCreateTime);
        return lqw;
    }

    /**
     * 新增物资
     */
    @Override
    public Boolean insertByBo(ErpMaterialBo bo) {
        ErpMaterial add = BeanUtil.toBean(bo, ErpMaterial.class);
        validEntityBeforeSave(add);
        if (null != add.getMaterialTypeId()) {
            ErpMaterialTypeVo materialTypeVo = materialTypeMapper.selectVoById(add.getMaterialTypeId());
            add.setMaterialTypeName(materialTypeVo.getTypeName());
        }
        if (null != add.getVendorId()) {
            ErpMaterialVendorVo materialVendorVo = materialVendorMapper.selectVoById(add.getVendorId());
            add.setVendorName(materialVendorVo.getVendorName());
        }
        if (null != add.getWarehouseLocationId()) {
            ErpWarehouseLocationVo warehouseLocationVo = warehouseLocationMapper.selectVoById(add.getWarehouseLocationId());
            add.setWarehouseLocationType(warehouseLocationVo.getLocationType());
            add.setWarehouseLocationCode(warehouseLocationVo.getLocationCode());
        }
        if (null != add.getWarehouseId()) {
            ErpWarehouseVo warehouseVo = warehouseMapper.selectVoById(add.getWarehouseId());
            add.setWarehouseId(warehouseVo.getId());
            add.setWarehouseName(warehouseVo.getName());
            add.setDeptId(warehouseVo.getDeptId());
            add.setDeptName(warehouseVo.getDeptName());
        }
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改物资
     */
    @Override
    public Boolean updateByBo(ErpMaterialBo bo) {
        ErpMaterial update = BeanUtil.toBean(bo, ErpMaterial.class);
        validEntityBeforeSave(update);
        if (baseMapper.selectById(update.getId()).getIsCheck().equals(IsEnableStatus.YES.getCode())) {
            throw new RuntimeException("更新失败，当前物料所在仓库正在盘点中，请在仓库盘点结束后再试！");
        }
        if (null != update.getMaterialTypeId()) {
            ErpMaterialTypeVo materialTypeVo = materialTypeMapper.selectVoById(update.getMaterialTypeId());
            update.setMaterialTypeName(materialTypeVo.getTypeName());
        }
        if (null != update.getVendorId()) {
            ErpMaterialVendorVo materialVendorVo = materialVendorMapper.selectVoById(update.getVendorId());
            update.setVendorName(materialVendorVo.getVendorName());
        }
        if (null != update.getWarehouseLocationId()) {
            ErpWarehouseLocationVo warehouseLocationVo = warehouseLocationMapper.selectVoById(update.getWarehouseLocationId());
            update.setWarehouseLocationType(warehouseLocationVo.getLocationType());
            update.setWarehouseLocationCode(warehouseLocationVo.getLocationCode());
        }
        if (null != update.getWarehouseId()) {
            ErpWarehouseVo warehouseVo = warehouseMapper.selectVoById(update.getWarehouseId());
            update.setWarehouseId(warehouseVo.getId());
            update.setWarehouseName(warehouseVo.getName());
            update.setDeptId(warehouseVo.getDeptId());
            update.setDeptName(warehouseVo.getDeptName());
        }
        return baseMapper.updateById(update) > 0;
    }


    /**
     * 同步更新物料库存
     * @param id 物料ID
     * @param quantity 数量
     * @param isAdd 增加或减少
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public synchronized boolean modifyMaterialInventory(long id, BigDecimal quantity, boolean isAdd) {
        ErpMaterial material = baseMapper.selectById(id);
        if (material == null) {
            throw new IllegalArgumentException("库存更新失败，物料不存在，请检查后再试！");
        }
        if (material.getIsCheck().equals(IsEnableStatus.YES.getCode())) {
            throw new IllegalArgumentException("库存更新失败，物料["+material.getMaterialName()+"]所在仓库正在盘点中，请在仓库盘点结束后再试！");
        }
        if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("数量必须为正数");
        }
        if (isAdd) {
            BigDecimal add = material.getInventory().add(quantity);
            material.setInventory(add);
            System.out.println("编号:[" + material.getMaterialCode() + "]名称:[" + material.getMaterialName() + "] 增加库存: +" + quantity + "，当前库存: " + add);
            baseMapper.updateById(material);
            return true;
        } else {
            BigDecimal subtract = material.getInventory().subtract(quantity);
            if (subtract.compareTo(BigDecimal.ZERO) < 0) {
                throw new RuntimeException("编号:[" + material.getMaterialCode() + "]名称:[" + material.getMaterialName() + "] 库存不足，当前库存: " + material.getInventory());
            }
            material.setInventory(subtract);
            System.out.println("编号:[" + material.getMaterialCode() + "]名称:[" + material.getMaterialName() + "] 减少库存: -" + quantity + "，当前库存: " + subtract);
            baseMapper.updateById(material);
            return true;
        }
    }


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

    /**
     * 批量删除物资
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        LambdaQueryWrapper<ErpMaterial> checkLambdaQueryWrapper = Wrappers.lambdaQuery();
        checkLambdaQueryWrapper.in(ErpMaterial::getId, ids).eq(ErpMaterial::getIsCheck, IsEnableStatus.YES.getCode());
        if (!baseMapper.selectList(checkLambdaQueryWrapper).isEmpty()) {
            throw new RuntimeException("物料所在仓库正在盘点中，请在仓库盘点结束后再试");
        }
        LambdaUpdateWrapper<ErpMaterial> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.in(ErpMaterial::getId, ids).set(ErpMaterial::getIsDelete, IsDeleteStatus.YES.getCode());
        return baseMapper.update(updateWrapper) > 0;
    }
}
