package com.maintain.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.maintain.business.domain.*;
import com.maintain.business.domain.bo.ErpMaterialPickingInfoBo;
import com.maintain.business.domain.vo.ErpMaterialPickingInfoVo;
import com.maintain.business.domain.vo.ErpMaterialPutawayInfoVo;
import com.maintain.business.mapper.*;
import com.maintain.business.service.IErpMaterialService;
import com.maintain.common.core.domain.BaseEntity;
import com.maintain.common.enums.IsEnableStatus;
import com.maintain.common.enums.PickingState;
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 lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.maintain.business.domain.bo.ErpMaterialPickingBo;
import com.maintain.business.domain.vo.ErpMaterialPickingVo;
import com.maintain.business.service.IErpMaterialPickingService;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 报修单-领料出库单Service业务层处理
 *
 * @author liushuai
 * @date 2025-04-01
 */
@RequiredArgsConstructor
@Service
public class ErpMaterialPickingServiceImpl implements IErpMaterialPickingService {

    private final ErpMaterialPickingMapper baseMapper;
    private final ErpMaterialPickingInfoMapper pickingInfoMapper;
    private final ErpMaterialPutawayInfoMapper putawayInfoMapper;
    private final ErpRepairFormMapper repairFormMapper;
    private final ErpCarMapper carMapper;
    private final IErpMaterialService materialService;
    private final ErpMaterialMapper materialMapper;

    /**
     * 查询报修单-领料出库单
     */
    @Override
    public ErpMaterialPickingVo queryById(Long id){
        ErpMaterialPickingVo materialVo = baseMapper.selectVoById(id);
        LambdaQueryWrapper<ErpMaterialPickingInfo> lqw = Wrappers.lambdaQuery();
        lqw.eq(ErpMaterialPickingInfo::getPickingId, id);
        List<ErpMaterialPickingInfoVo> infoVoList = pickingInfoMapper.selectVoList(lqw);
        if (!infoVoList.isEmpty()) {
            materialVo.setPickingInfoList(infoVoList);
        }
        return materialVo;
    }

    /**
     * 查询报修单-领料出库单列表
     */
    @Override
    public TableDataInfo<ErpMaterialPickingVo> queryPageList(ErpMaterialPickingBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ErpMaterialPicking> lqw = buildQueryWrapper(bo);
        Page<ErpMaterialPickingVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询物料出库列表(包含明细)
     *
     * @param bo
     * @param pageQuery
     */
    @Override
    public TableDataInfo<ErpMaterialPickingVo> queryPageInfoList(ErpMaterialPickingBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ErpMaterialPicking> lqw = buildQueryWrapper(bo);
        Page<ErpMaterialPickingVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        // 查询出库明细列表
        LambdaQueryWrapper<ErpMaterialPickingInfo> queryWrapper = Wrappers.lambdaQuery();
        for (ErpMaterialPickingVo pickingVo : result.getRecords()) {
            queryWrapper.eq(ErpMaterialPickingInfo::getPickingId, pickingVo.getId());
            List<ErpMaterialPickingInfoVo> infoVoList = pickingInfoMapper.selectVoList(queryWrapper);
            for (ErpMaterialPickingInfoVo infoVo : infoVoList) {
                LambdaQueryWrapper<ErpMaterialPutawayInfo> putawayInfoLambdaQueryWrapper = Wrappers.lambdaQuery();
                putawayInfoLambdaQueryWrapper.eq(ErpMaterialPutawayInfo::getMaterialId, infoVo.getMaterialId());
                List<ErpMaterialPutawayInfoVo> putawayInfoVos = putawayInfoMapper.selectVoList(putawayInfoLambdaQueryWrapper);
                Set<BigDecimal> priceSet = putawayInfoVos.stream().map(ErpMaterialPutawayInfoVo::getPutawayPrice).collect(Collectors.toSet());
                infoVo.setPriceList(priceSet);
            }
            pickingVo.setPickingInfoList(infoVoList);
        }
        return TableDataInfo.build(result);
    }

    /**
     * 查询报修单-领料出库单列表
     */
    @Override
    public List<ErpMaterialPickingVo> queryList(ErpMaterialPickingBo bo) {
        LambdaQueryWrapper<ErpMaterialPicking> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<ErpMaterialPicking> buildQueryWrapper(ErpMaterialPickingBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ErpMaterialPicking> lqw = Wrappers.lambdaQuery();
        lqw.eq( bo.getType() != null, ErpMaterialPicking::getType, bo.getType());
        lqw.eq(bo.getSettlementState() != null, ErpMaterialPicking::getSettlementState, bo.getSettlementState());
        lqw.eq(bo.getRepairFormId() != null, ErpMaterialPicking::getRepairFormId, bo.getRepairFormId());
        lqw.like(StringUtils.isNotBlank(bo.getRepairNumber()), ErpMaterialPicking::getRepairNumber, bo.getRepairNumber());
        lqw.like(StringUtils.isNotBlank(bo.getReturnNumber()), ErpMaterialPicking::getReturnNumber, bo.getReturnNumber());
        lqw.like(StringUtils.isNotBlank(bo.getOutNumber()), ErpMaterialPicking::getOutNumber, bo.getOutNumber());
        lqw.eq(bo.getCarId() != null, ErpMaterialPicking::getCarId, bo.getCarId());
        lqw.like(StringUtils.isNotBlank(bo.getPlateNumber()), ErpMaterialPicking::getPlateNumber, bo.getPlateNumber());
        lqw.eq(bo.getOutMoney() != null, ErpMaterialPicking::getOutMoney, bo.getOutMoney());
        lqw.eq(bo.getReceiveUserId() != null, ErpMaterialPicking::getReceiveUserId, bo.getReceiveUserId());
        lqw.like(StringUtils.isNotBlank(bo.getReceiveUserName()), ErpMaterialPicking::getReceiveUserName, bo.getReceiveUserName());
        lqw.eq(bo.getReceiveTime() != null, ErpMaterialPicking::getReceiveTime, bo.getReceiveTime());
        lqw.eq(bo.getState() != null, ErpMaterialPicking::getState, bo.getState());
        lqw.in(bo.getStateList() != null, ErpMaterialPicking::getState, bo.getStateList());
        lqw.orderByDesc(BaseEntity::getCreateTime);
        return lqw;
    }

    /**
     * 新增领料出库单
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean insertByBo(ErpMaterialPickingBo bo) {
        ErpMaterialPicking add = BeanUtil.toBean(bo, ErpMaterialPicking.class);
        ErpRepairForm repairForm = repairFormMapper.selectById(bo.getRepairFormId());
        ErpCar erpCar = carMapper.selectById(repairForm.getCarId());
        add.setCarId(erpCar.getId());
        add.setOutNumber(RedisUtils.generateNextNumber("CK"));
        add.setRepairNumber(repairForm.getRepairNumber());
        add.setPlateNumber(erpCar.getPlateNumber());
        add.setReceiveUserId(LoginHelper.getUserId());
        add.setReceiveUserName(LoginHelper.getUsername());
        add.setReceiveTime(new Date());
        BigDecimal moneyTotal = bo.getMaterialList().stream().map(ErpMaterialPickingInfoBo::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        add.setOutMoney(moneyTotal);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            List<ErpMaterialPickingInfoBo> infoBoList = bo.getMaterialList();
            List<ErpMaterialPickingInfo> collect = infoBoList.stream().map(item -> {
                ErpMaterialPickingInfo info = BeanUtil.toBean(item, ErpMaterialPickingInfo.class);
                ErpMaterial material = materialMapper.selectById(item.getMaterialId());
                BeanUtil.copyProperties(material, info);
                info.setId(null);
                info.setRepairFormId(bo.getRepairFormId());
                info.setPickingId(add.getId());
                info.setState(bo.getState());
                // 更新物料库存
                if (bo.getState().equals(PickingState.TWO.getCode())) {
                    materialService.modifyMaterialInventory(item.getMaterialId(), item.getCollectNumber(), false);
                }
                return info;
            }).collect(Collectors.toList());
            pickingInfoMapper.insertBatch(collect);
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改领料出库单
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateByBo(ErpMaterialPickingBo bo) {
        ErpMaterialPicking update = BeanUtil.toBean(bo, ErpMaterialPicking.class);
        BigDecimal moneyTotal = bo.getMaterialList().stream().map(ErpMaterialPickingInfoBo::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
        ErpRepairForm repairForm = repairFormMapper.selectById(bo.getRepairFormId());
        ErpCar erpCar = carMapper.selectById(repairForm.getCarId());
        update.setCarId(erpCar.getId());
        update.setRepairNumber(repairForm.getRepairNumber());
        update.setPlateNumber(erpCar.getPlateNumber());
        update.setOutMoney(moneyTotal);
        validEntityBeforeSave(update);
        boolean flag = baseMapper.updateById(update) > 0;
        if (flag) {
            // 删除原有绑定
            LambdaQueryWrapper<ErpMaterialPickingInfo> lqw = Wrappers.lambdaQuery();
            lqw.eq(ErpMaterialPickingInfo::getPickingId, update.getId());
            pickingInfoMapper.delete(lqw);

            // 批量新增材料明细
            List<ErpMaterialPickingInfoBo> infoBoList = bo.getMaterialList();
            List<ErpMaterialPickingInfo> collect = infoBoList.stream().map(item -> {
                ErpMaterialPickingInfo info = BeanUtil.toBean(item, ErpMaterialPickingInfo.class);
                ErpMaterial material = materialMapper.selectById(item.getMaterialId());
                BeanUtil.copyProperties(material, info);
                info.setId(null);
                info.setPickingId(update.getId());
                info.setRepairFormId(update.getRepairFormId());
                info.setState(bo.getState());
                // 更新物料库存
                if (bo.getState().equals(PickingState.TWO.getCode())) {
                    materialService.modifyMaterialInventory(item.getMaterialId(), item.getCollectNumber(), false);
                }
                return info;
            }).collect(Collectors.toList());
            pickingInfoMapper.insertBatch(collect);
        }
        return flag;
    }

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

    /**
     * 批量删除领料出库单
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        // 删除领料出库单
        boolean flag = baseMapper.deleteBatchIds(ids) > 0;
        if (flag) {
            // 更新物料库存
            LambdaQueryWrapper<ErpMaterialPickingInfo> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.in(ErpMaterialPickingInfo::getPickingId, ids);
            List<ErpMaterialPickingInfoVo> pickingInfoVoList = pickingInfoMapper.selectVoList(queryWrapper);
            for (ErpMaterialPickingInfoVo infoVo : pickingInfoVoList) {
                if (infoVo.getState().equals(PickingState.TWO.getCode())) {
                    materialService.modifyMaterialInventory(infoVo.getMaterialId(), infoVo.getCollectNumber(), false);
                }
            }
            // 删除领料出库单明细
            LambdaUpdateWrapper<ErpMaterialPickingInfo> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.in(ErpMaterialPickingInfo::getPickingId, ids);
            pickingInfoMapper.delete(updateWrapper);
        }
        return flag;
    }

    /**
     * 批量确认物料出库
     *
     * @param ids
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean confirmByIds(Collection<Long> ids) {
        // 更新物料出库状态
        LambdaUpdateWrapper<ErpMaterialPicking> lqw = Wrappers.lambdaUpdate();
        lqw.in(ErpMaterialPicking::getId, ids);
        lqw.set(ErpMaterialPicking::getState, PickingState.TWO.getCode());
        boolean flag = baseMapper.update(lqw) > 0;
        if (flag) {
            // 更新出库明细状态
            LambdaUpdateWrapper<ErpMaterialPickingInfo> updateWrapper = Wrappers.lambdaUpdate();
            updateWrapper.in(ErpMaterialPickingInfo::getPickingId, ids).set(ErpMaterialPickingInfo::getState, PickingState.TWO.getCode());
            pickingInfoMapper.update(updateWrapper);

            // 更新物料库存
            LambdaQueryWrapper<ErpMaterialPickingInfo> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.in(ErpMaterialPickingInfo::getPickingId, ids).eq(ErpMaterialPickingInfo::getState, PickingState.ONE.getCode());
            List<ErpMaterialPickingInfoVo> pickingInfoVoList = pickingInfoMapper.selectVoList(queryWrapper);
            for (ErpMaterialPickingInfoVo infoVo : pickingInfoVoList) {
                materialService.modifyMaterialInventory(infoVo.getMaterialId(), infoVo.getCollectNumber(), false);
            }
        }
        return flag;
    }

    /**
     * 新增物料出库退料单
     *
     * @param bo
     */
    @Override
    public Boolean insertReturnByBo(ErpMaterialPickingBo bo) {
        ErpMaterialPicking materialPicking = baseMapper.selectById(bo.getId());
        materialPicking.setReturnNumber(RedisUtils.generateNextNumber("TL"));
        materialPicking.setReturnTime(new Date());
        // 如果领料单状态已完成，if需要更新物料库存以及领料出库明细状态,else只需要更新领料出库明细状态
        LambdaUpdateWrapper<ErpMaterialPickingInfo> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(ErpMaterialPickingInfo::getPickingId, bo.getId());
        updateWrapper.set(ErpMaterialPickingInfo::getState, PickingState.THREE.getCode());
        if (materialPicking.getState().equals(PickingState.TWO.getCode())) {
            LambdaQueryWrapper<ErpMaterialPickingInfo> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(ErpMaterialPickingInfo::getPickingId, bo.getId());
            List<ErpMaterialPickingInfoVo> pickingInfoVoList = pickingInfoMapper.selectVoList(queryWrapper);
            for (ErpMaterialPickingInfoVo infoVo : pickingInfoVoList) {
                // 更新物料库存
                materialService.modifyMaterialInventory(infoVo.getMaterialId(), infoVo.getCollectNumber(), true);
            }
        }
        // 更新领料出库明细状态
        pickingInfoMapper.update(updateWrapper);
        // 更新领料出库单状态
        materialPicking.setState(PickingState.THREE.getCode());
        return baseMapper.updateById(materialPicking) > 0;
    }
}
