package org.jeecg.modules.material.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.util.DateUtils;
import org.jeecg.modules.api.model.CabinetStocks;
import org.jeecg.modules.material.entity.BuMaterialInfo;
import org.jeecg.modules.material.entity.BuMaterialSheet;
import org.jeecg.modules.material.entity.BuMaterialStock;
import org.jeecg.modules.material.mapper.BuMaterialInfoMapper;
import org.jeecg.modules.material.mapper.BuMaterialSheetMapper;
import org.jeecg.modules.material.mapper.BuMaterialStockMapper;
import org.jeecg.modules.material.model.bo.BuMaterialStockBo;
import org.jeecg.modules.material.service.IBuMaterialStockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.jeewx.api.core.util.DateUtils.datetimeFormat;

/**
 * @Description: 物料出入库记录
 * @Author: jeecg-boot
 * @Date:   2025-01-15
 * @Version: V1.0
 */
@AllArgsConstructor
@Service
public class BuMaterialStockServiceImpl extends ServiceImpl<BuMaterialStockMapper, BuMaterialStock> implements IBuMaterialStockService {

    private BuMaterialSheetMapper materialSheetMapper;
    private BuMaterialInfoMapper materialInfoMapper;

    /**
     * 新增物料出入库记录
     *
     * @param bo 物料出入库记录
     * @return 是否新增成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean insertByBo(BuMaterialStockBo bo) {
        BuMaterialStock add = BeanUtil.toBean(bo, BuMaterialStock.class);
        if(!save(add)){
            return false;
        }
        // 物料台账
        // todo 添加批次号和每批次采购时间的逻辑
        BuMaterialSheet materialSheet = materialSheetMapper.selectOne(new LambdaQueryWrapper<BuMaterialSheet>()
                .eq(BuMaterialSheet::getMaterialId, add.getMaterialId()).eq(BuMaterialSheet::getBrand,bo.getBrand()));
        if(ObjectUtil.isNotNull(materialSheet)){
            materialSheet.setQuantity(materialSheet.getQuantity()+add.getQuantity());
        }else {
            materialSheet = new BuMaterialSheet();
            BuMaterialInfo materialInfoVo = materialInfoMapper.selectById(add.getMaterialId());
            materialSheet.setMaterialId(add.getMaterialId());
            materialSheet.setBrand(bo.getBrand());
            materialSheet.setModel(materialInfoVo.getSpecifaction());
            materialSheet.setVendor(bo.getVendor());
            materialSheet.setPurchaseDate(add.getAlterTime());
            materialSheet.setQuantity(add.getQuantity());
            materialSheet.setCabinet(bo.getCabinet());
            materialSheet.setBatchNum(add.getBatchNum());
        }
        if(StringUtils.isBlank(materialSheet.getId())) {
            return materialSheetMapper.insert(materialSheet)>0;
        }else {
            return materialSheetMapper.updateById(materialSheet)>0;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean materialStock(List<BuMaterialStockBo> bos) {
        if (CollectionUtils.isEmpty(bos)) {
            return true;
        }

        // 1. 批量保存库存流水
        List<BuMaterialStock> stockList = new ArrayList<>(bos.size());
        for (BuMaterialStockBo bo : bos) {
            BuMaterialStock stock = BeanUtil.toBean(bo, BuMaterialStock.class);
            if (!save(stock)) {
                throw new RuntimeException("保存物料库存流水失败: " + bo);
            }
            stockList.add(stock);
        }

        // 2. 批量查询关联的物料表记录（去重 key: materialId + model）
        Set<String> uniqueKeys = bos.stream()
                .map(bo -> bo.getMaterialId() + "::" + bo.getModel())
                .collect(Collectors.toSet());

        List<BuMaterialSheet> existingSheets = materialSheetMapper.selectList(
                new LambdaQueryWrapper<BuMaterialSheet>()
                        .in(BuMaterialSheet::getMaterialId,
                                bos.stream().map(BuMaterialStockBo::getMaterialId).distinct().toList())
                        .in(BuMaterialSheet::getModel,
                                bos.stream().map(BuMaterialStockBo::getModel).distinct().toList())
        );

        // 构建 map 用于快速查找（key: materialId + model）
        Map<String, BuMaterialSheet> sheetMap = existingSheets.stream()
                .collect(Collectors.toMap(
                        sheet -> sheet.getMaterialId() + "::" + sheet.getModel(),
                        Function.identity(),
                        (oldVal, newVal) -> oldVal // 防冲突，实际不应重复
                ));

        // 3. 按 BO 更新库存数量
        for (BuMaterialStockBo bo : bos) {
            String key = bo.getMaterialId() + "::" + bo.getModel();
            BuMaterialSheet sheet = sheetMap.get(key);

            if (sheet == null) {
                // 可选：是否允许自动创建？根据业务决定
                throw new RuntimeException(String.format(
                        "物料表中不存在 [materialId=%s, model=%s] 的记录，无法更新库存",
                        bo.getMaterialId(), bo.getModel()
                ));
            }

            BuMaterialStock stock = BeanUtil.toBean(bo, BuMaterialStock.class); // 或从 stockList 获取对应项
            double delta = bo.getType() == 0 ? -stock.getQuantity() : stock.getQuantity();
            sheet.setQuantity(sheet.getQuantity() + delta);
            sheet.setPurchaseDate(bo.getAlterTime());
        }

        // 4. 批量更新物料表（MyBatis-Plus 支持批量 update）
        boolean updated = materialSheetMapper.updateBatch(sheetMap.values().stream().toList())>0;
        if (!updated) {
            throw new RuntimeException("批量更新物料库存失败");
        }

        return true;
    }

    @Autowired
    private ISysBaseAPI baseAPI;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean inOutRecordSync(List<CabinetStocks> records) {
        int count = 0;
        for (CabinetStocks record : records) {
            switch (record.getOpType()) {
                case 0:// 出库操作
                    count += processOutRecord(record);
                    break;
                case 1://若是一条入库记录则需要找到对应的出库记录并更新
                    count += processInRecord(record);
                    break;
                default:
                    // 处理未知操作类型
                    log.error("未知出入库操作类型："+record.getOpType());
                    break;
            }
        }
        return count == records.size();
    }

    /**
     * 处理出库操作
     */
    private int processOutRecord(CabinetStocks record) {
        // 查询基础台账信息
        BuMaterialSheet materialSheet = materialSheetMapper.selectOne(new LambdaQueryWrapper<BuMaterialSheet>().eq(BuMaterialSheet::getMaterialId, record.getMaterialId()));
        if (materialSheet == null || materialSheet.getQuantity() < record.getOpNumber()) {
            log.error("台账不存在或库存不足，物料ID：" + record.getMaterialId());
            return 0;// 台账不存在或库存不足
        }

        // 创建出库记录
        BuMaterialStock materialStock = convertToMaterialStock(record);
        if (!super.save(materialStock)) {
            return 0; // 保存失败
        }

        // 更新台账
        return updateMaterialSheetQuantity(materialSheet, -record.getOpNumber()) ? 1 : 0;
    }

    /**
     * 处理入库操作
     */
    private int processInRecord(CabinetStocks record) {
        // 查询基础台账信息
        BuMaterialSheet materialSheet = materialSheetMapper.selectOne(new LambdaQueryWrapper<BuMaterialSheet>().eq(BuMaterialSheet::getMaterialId, record.getMaterialId()));
        if (materialSheet == null) {
            log.error("台账不存在，物料ID：" + record.getMaterialId());
            return 0; // 台账不存在
        }
        // 创建入库记录
        BuMaterialStock materialStock = convertToMaterialStock(record);
        if (!super.save(materialStock)) {
            return 0; // 保存失败
        }

        // 更新台账
        return updateMaterialSheetQuantity(materialSheet, record.getOpNumber()) ? 1 : 0;
    }
    /**
     * 更新台账数量
     *
     * @param materialSheet 台账对象
     * @param delta         数量变化（正数为增加，负数为减少）
     * @return 是否更新成功
     */
    private boolean updateMaterialSheetQuantity(BuMaterialSheet materialSheet, double delta) {
        materialSheet.setQuantity(materialSheet.getQuantity() + delta);
        materialSheet.setPurchaseDate(DateUtils.getDate());
        return materialSheetMapper.updateById(materialSheet) > 0;
    }
    private BuMaterialStock convertToMaterialStock(CabinetStocks record) {
        BuMaterialStock materialStock = new BuMaterialStock();
        materialStock.setMaterialId(record.getMaterialId());
        materialStock.setWorkOrder(record.getOrderId());
        materialStock.setOperator(record.getUserId());
        materialStock.setType(record.getOpType());
        materialStock.setAlterTime(DateUtils.str2Date(record.getOpTime(), datetimeFormat));
        materialStock.setQuantity(record.getOpNumber());
        return materialStock;
    }

}
