package com.zt.plat.module.erp.service.erp;

import cn.hutool.core.collection.CollUtil;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.zt.plat.module.erp.utils.ErpConfig;
import com.zt.plat.module.erp.utils.MyRedisConfig;
import com.zt.plat.module.erp.enums.OftenEnum;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpBomDetailPageReqVO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpBomDetailRespVO;
import com.zt.plat.module.erp.controller.admin.erp.vo.ErpBomDetailSaveReqVO;
import com.zt.plat.module.erp.dal.dataobject.erp.ErpBomDetailDO;
import com.zt.plat.module.erp.dal.mysql.erp.ErpBomDetailMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.erp.enums.ErrorCodeConstants.ERP_BOM_DETAIL_NOT_EXISTS;

/**
 * ERP物料清单(BOM)明细 Service 实现类
 *
 * @author 后台管理
 */
@Service
@Validated
public class ErpBomDetailServiceImpl implements ErpBomDetailService {

    @Resource
    private ErpBomDetailMapper erpBomDetailMapper;

    @Resource
    private MyRedisConfig myRedisConfig;
    @Resource
    private ErpConfig erpConfig;

    @Override
    public ErpBomDetailRespVO createErpBomDetail(ErpBomDetailSaveReqVO createReqVO) {
        // 插入
        ErpBomDetailDO erpBomDetail = BeanUtils.toBean(createReqVO, ErpBomDetailDO.class);
        erpBomDetailMapper.insert(erpBomDetail);
        // 返回
        return BeanUtils.toBean(erpBomDetail, ErpBomDetailRespVO.class);
    }

    @Override
    public void updateErpBomDetail(ErpBomDetailSaveReqVO updateReqVO) {
        // 校验存在
        validateErpBomDetailExists(updateReqVO.getId());
        // 更新
        ErpBomDetailDO updateObj = BeanUtils.toBean(updateReqVO, ErpBomDetailDO.class);
        erpBomDetailMapper.updateById(updateObj);
    }

    @Override
    public void deleteErpBomDetail(Long id) {
        // 校验存在
        validateErpBomDetailExists(id);
        // 删除
        erpBomDetailMapper.deleteById(id);
    }

    @Override
    public void deleteErpBomDetailListByIds(List<Long> ids) {
        // 校验存在
        validateErpBomDetailExists(ids);
        // 删除
        erpBomDetailMapper.deleteByIds(ids);
    }

    private void validateErpBomDetailExists(List<Long> ids) {
        List<ErpBomDetailDO> list = erpBomDetailMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(ERP_BOM_DETAIL_NOT_EXISTS);
        }
    }

    private void validateErpBomDetailExists(Long id) {
        if (erpBomDetailMapper.selectById(id) == null) {
            throw exception(ERP_BOM_DETAIL_NOT_EXISTS);
        }
    }

    @Override
    public ErpBomDetailDO getErpBomDetail(Long id) {
        return erpBomDetailMapper.selectById(id);
    }

    @Override
    public PageResult<ErpBomDetailDO> getErpBomDetailPage(ErpBomDetailPageReqVO pageReqVO) {
        return erpBomDetailMapper.selectPage(pageReqVO);
    }

    @Override
    public void saveOrUpdateErpBomDetail(List<ErpBomDetailDO> updateReqVOS) {
        String key = "erpMap" + OftenEnum.FuncnrEnum.BOM清单.getFuncnr() + "Detail";
        // 1. 处理公司数据，区分新增和更新
        ProcessingResult result = processData(updateReqVOS, key);

        // 2. 批量保存数据
        saveData(result);
    }

    private ProcessingResult processData(List<ErpBomDetailDO> updateReqVOS, String key) {
        if (myRedisConfig.getRedisCacheMap(key).isEmpty()) {
            initializeMap(key);
        }
        List<ErpBomDetailDO> toUpdate = new ArrayList<>();
        List<ErpBomDetailDO> toInsert = new ArrayList<>();

        List<String> dataArrayNumbers = new ArrayList<>();
        Map<String, Long> existingNumbers = myRedisConfig.getRedisCacheMap(key);
        for (ErpBomDetailDO updateReqVO : updateReqVOS) {
            String mapKey = updateReqVO.getBomId() + "-" + updateReqVO.getErpBomId();
            if (existingNumbers.containsKey(mapKey)) {
                updateReqVO.setId(existingNumbers.get(mapKey));
            }
            if (updateReqVO.getId() == null) {
                toInsert.add(updateReqVO);
            } else {
                toUpdate.add(updateReqVO);
            }
            dataArrayNumbers.add(mapKey);
        }

        Map<String, Long> deleteNumbers = new HashMap<>();
        for (Map.Entry<String, Long> entry : existingNumbers.entrySet()) {
            if (!dataArrayNumbers.contains(entry.getKey())) {
                deleteNumbers.put(entry.getKey(), entry.getValue());
            }
        }

        return new ProcessingResult(toUpdate, toInsert, deleteNumbers, key);
    }

    private void saveData(ProcessingResult result) {
        // 批量新增和更新
        if (!result.toInsert.isEmpty()) {
            erpBomDetailMapper.insertBatch(result.toInsert);
            // 批量查询刚插入数据的id，提升效率
            List<ErpBomDetailDO> insertedRecords = erpBomDetailMapper.selectList(
                    new LambdaQueryWrapperX<ErpBomDetailDO>()
                            .in(ErpBomDetailDO::getBomId, result.toInsert.stream().map(ErpBomDetailDO::getBomId).distinct().collect(Collectors.toList()))
                            .in(ErpBomDetailDO::getErpBomId, result.toInsert.stream().map(ErpBomDetailDO::getErpBomId).distinct().collect(Collectors.toList()))
            );
            Map<String, Long> numberIdMap = insertedRecords.stream()
                    .collect(Collectors.toMap(asset -> asset.getBomId() + "-" + asset.getErpBomId(), ErpBomDetailDO::getId));
            myRedisConfig.addRedisCacheMap(result.key, numberIdMap);
        }
        if (!result.toUpdate.isEmpty()) {
            erpBomDetailMapper.updateBatch(result.toUpdate);
        }
        if (!result.deleteNumbers.isEmpty()) {
            // 使用流式处理和批处理优化删除逻辑
            List<Long> idsToDelete = new ArrayList<>(result.deleteNumbers.values());
            if (!idsToDelete.isEmpty()) {
                erpBomDetailMapper.deleteByIds(idsToDelete);
            }
            myRedisConfig.deleteRedisCacheMap(result.key, new ArrayList<>(result.deleteNumbers.keySet()));
        }
    }

    private static class ProcessingResult {
        private final List<ErpBomDetailDO> toUpdate;
        private final List<ErpBomDetailDO> toInsert;
        private final Map<String, Long> deleteNumbers;
        private final String key;

        public ProcessingResult(List<ErpBomDetailDO> toUpdate, List<ErpBomDetailDO> toInsert, Map<String, Long> deleteNumbers, String key) {
            this.toUpdate = toUpdate;
            this.toInsert = toInsert;
            this.deleteNumbers = deleteNumbers;
            this.key = key;
        }
    }

    private void initializeMap(String key) {
        List<ErpBomDetailDO> assets = erpBomDetailMapper.selectList(new LambdaQueryWrapperX<ErpBomDetailDO>());
        Map<String, Long> existingNumbers = new HashMap<>();
        for (ErpBomDetailDO asset : assets) {
            String mapKey = asset.getBomId() + "-" + asset.getErpBomId();
            existingNumbers.put(mapKey, asset.getId());
        }
        myRedisConfig.addRedisCacheMap(key, existingNumbers);
    }
}