package cn.iocoder.yudao.module.system.service.biz;

import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.material.MaterialInfoPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.material.MaterialInfoRespVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.material.MaterialInfoSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.material.MaterialInfoUpdateStatusReqVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.material.excel.MaterialInfoImportExcelVO;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.MaterialCategoryDO;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.MaterialInfoDO;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.StoreManageDO;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.SupplierInfoDO;
import cn.iocoder.yudao.module.system.dal.mysql.biz.MaterialCategoryMapper;
import cn.iocoder.yudao.module.system.dal.mysql.biz.MaterialInfoMapper;
import cn.iocoder.yudao.module.system.dal.mysql.biz.StoreManageMapper;
import cn.iocoder.yudao.module.system.dal.mysql.biz.SupplierInfoMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.COMMON_NOT_FOUND;

@Service
@Validated
public class MaterialInfoServiceImpl implements MaterialInfoService {

    @Resource
    private MaterialInfoMapper materialInfoMapper;

    @Resource
    private MaterialCategoryMapper materialCategoryMapper;

    @Resource
    private StoreManageMapper storeManageMapper;

    @Resource
    private SupplierInfoMapper supplierInfoMapper;

    @Override
    public Long createMaterialInfo(MaterialInfoSaveReqVO createReqVO) {
        // 默认启用
        if (createReqVO.getStatus() == null) {
            createReqVO.setStatus(1);
        }
        // 唯一校验：同 tenantId 下 materialNumber 不允许重复
        validateMaterialNumberUnique(null, createReqVO.getTenantId(), createReqVO.getMaterialNumber());

        MaterialInfoDO materialInfo = BeanUtils.toBean(createReqVO, MaterialInfoDO.class);
        materialInfoMapper.insert(materialInfo);
        return materialInfo.getId();
    }

    @Override
    public void updateMaterialInfo(MaterialInfoSaveReqVO updateReqVO) {
        validateMaterialInfoExists(updateReqVO.getId());
        // 唯一校验：同 tenantId 下 materialNumber 不允许重复（排除自己）
        validateMaterialNumberUnique(updateReqVO.getId(), updateReqVO.getTenantId(), updateReqVO.getMaterialNumber());

        MaterialInfoDO updateObj = BeanUtils.toBean(updateReqVO, MaterialInfoDO.class);
        materialInfoMapper.updateById(updateObj);
    }

    @Override
    public void updateMaterialInfoStatus(MaterialInfoUpdateStatusReqVO reqVO) {
        validateMaterialInfoExists(reqVO.getId());
        MaterialInfoDO updateObj = new MaterialInfoDO();
        updateObj.setId(reqVO.getId());
        updateObj.setStatus(reqVO.getStatus());
        materialInfoMapper.updateById(updateObj);
    }

    @Override
    public void deleteMaterialInfo(Long id) {
        validateMaterialInfoExists(id);
        materialInfoMapper.deleteById(id);
    }

    @Override
    public MaterialInfoRespVO getMaterialInfo(Long id) {
        MaterialInfoRespVO resp = materialInfoMapper.selectMaterialInfoById(id);
        if (resp == null) {
            throw exception(COMMON_NOT_FOUND);
        }
        return resp;
    }

    @Override
    public PageResult<MaterialInfoRespVO> getMaterialInfoPage(MaterialInfoPageReqVO pageReqVO) {
        com.baomidou.mybatisplus.extension.plugins.pagination.Page<Object> page =
                new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        java.util.List<MaterialInfoRespVO> list = materialInfoMapper.selectMaterialInfoPage(page, pageReqVO);
        return new PageResult<>(list, page.getTotal());
    }

    @Override
    public List<MaterialInfoRespVO> getMaterialList(Long tenantId) {
        return materialInfoMapper.selectMaterialInfoByTenantId(tenantId);
    }

    private void validateMaterialInfoExists(Long id) {
        if (id == null || materialInfoMapper.selectById(id) == null) {
            throw exception(COMMON_NOT_FOUND);
        }
    }

    /**
     * 校验同租户下物资编号唯一
     */
    private void validateMaterialNumberUnique(Long id, Long tenantId, String materialNumber) {
        MaterialInfoDO exists = materialInfoMapper.selectOne(new LambdaQueryWrapperX<MaterialInfoDO>()
                .eq(MaterialInfoDO::getTenantId, tenantId)
                .eq(MaterialInfoDO::getMaterialNumber, materialNumber)
                .neIfPresent(MaterialInfoDO::getId, id));
        if (exists != null) {
            // 复用通用"已存在"错误码
            throw exception(cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.COMMON_EXIST_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> importMaterialInfoExcel(List<MaterialInfoImportExcelVO> list) {
        Long tenantId = TenantContextHolder.getTenantId();
        List<MaterialInfoImportExcelVO> errorList = new ArrayList<>();
        int successCount = 0;

        // 预加载所有类别、仓库、供应商数据，建立名称到ID的映射
        Map<String, Long> categoryNameToIdMap = materialCategoryMapper.selectList(
                new LambdaQueryWrapperX<MaterialCategoryDO>()
                        .eq(MaterialCategoryDO::getTenantId, tenantId))
                .stream()
                .collect(Collectors.toMap(MaterialCategoryDO::getCategoryName, MaterialCategoryDO::getId, (v1, v2) -> v1));

        Map<String, Long> storeNameToIdMap = storeManageMapper.selectList(
                new LambdaQueryWrapperX<StoreManageDO>()
                        .eq(StoreManageDO::getTenantId, tenantId))
                .stream()
                .collect(Collectors.toMap(StoreManageDO::getStoreName, StoreManageDO::getId, (v1, v2) -> v1));

        Map<String, Long> supplierNameToIdMap = supplierInfoMapper.selectList(
                new LambdaQueryWrapperX<SupplierInfoDO>()
                        .eq(SupplierInfoDO::getTenantId, tenantId))
                .stream()
                .collect(Collectors.toMap(SupplierInfoDO::getSupplierName, SupplierInfoDO::getId, (v1, v2) -> v1));

        // 遍历导入数据
        for (int i = 0; i < list.size(); i++) {
            MaterialInfoImportExcelVO excelVO = list.get(i);
            StringBuilder errorMsg = new StringBuilder();

            // 1. 校验必填字段
            if (excelVO.getMaterialNumber() == null || excelVO.getMaterialNumber().trim().isEmpty()) {
                errorMsg.append("物资编号不能为空；");
            }
            if (excelVO.getMaterialName() == null || excelVO.getMaterialName().trim().isEmpty()) {
                errorMsg.append("物资名称不能为空；");
            }
            if (excelVO.getCategoryName() == null || excelVO.getCategoryName().trim().isEmpty()) {
                errorMsg.append("物资类别不能为空；");
            }
            if (excelVO.getStoreName() == null || excelVO.getStoreName().trim().isEmpty()) {
                errorMsg.append("仓库名称不能为空；");
            }

            // 2. 校验类别是否存在
            Long categoryId = null;
            if (excelVO.getCategoryName() != null && !excelVO.getCategoryName().trim().isEmpty()) {
                categoryId = categoryNameToIdMap.get(excelVO.getCategoryName().trim());
                if (categoryId == null) {
                    errorMsg.append("物资类别【").append(excelVO.getCategoryName()).append("】不存在；");
                }
            }

            // 3. 校验仓库是否存在
            Long storeId = null;
            if (excelVO.getStoreName() != null && !excelVO.getStoreName().trim().isEmpty()) {
                storeId = storeNameToIdMap.get(excelVO.getStoreName().trim());
                if (storeId == null) {
                    errorMsg.append("仓库名称【").append(excelVO.getStoreName()).append("】不存在；");
                }
            }

            // 4. 校验供应商是否存在（可选）
            Long supplierId = null;
            if (excelVO.getSupplierName() != null && !excelVO.getSupplierName().trim().isEmpty()) {
                supplierId = supplierNameToIdMap.get(excelVO.getSupplierName().trim());
                if (supplierId == null) {
                    errorMsg.append("供应商名称【").append(excelVO.getSupplierName()).append("】不存在；");
                }
            }

            // 如果有错误，记录到错误列表
            if (errorMsg.length() > 0) {
                excelVO.setErrorMsg(errorMsg.toString());
                errorList.add(excelVO);
                continue;
            }

            // 5. 校验物资编号唯一性（同租户下）
            MaterialInfoDO existingMaterial = materialInfoMapper.selectOne(
                    new LambdaQueryWrapperX<MaterialInfoDO>()
                            .eq(MaterialInfoDO::getTenantId, tenantId)
                            .eq(MaterialInfoDO::getMaterialNumber, excelVO.getMaterialNumber().trim()));

            MaterialInfoDO materialInfo;
            if (existingMaterial != null) {
                // 更新已存在的物资
                materialInfo = existingMaterial;
                materialInfo.setMaterialName(excelVO.getMaterialName().trim());
                materialInfo.setCategoryId(categoryId);
                materialInfo.setStoreId(storeId);
                materialInfo.setMaterialUnit(excelVO.getMaterialUnit());
                materialInfo.setSupplierId(supplierId);
                materialInfo.setSpecification(excelVO.getSpecification());
                materialInfo.setMaxNum(excelVO.getMaxNum());
                materialInfo.setMinNum(excelVO.getMinNum());
                materialInfo.setShelfLife(excelVO.getShelfLife());
                // 默认启用
                if (materialInfo.getStatus() == null) {
                    materialInfo.setStatus(1);
                }
                materialInfoMapper.updateById(materialInfo);
            } else {
                // 新增物资
                materialInfo = new MaterialInfoDO();
                materialInfo.setMaterialNumber(excelVO.getMaterialNumber().trim());
                materialInfo.setMaterialName(excelVO.getMaterialName().trim());
                materialInfo.setCategoryId(categoryId);
                materialInfo.setStoreId(storeId);
                materialInfo.setMaterialUnit(excelVO.getMaterialUnit());
                materialInfo.setSupplierId(supplierId);
                materialInfo.setSpecification(excelVO.getSpecification());
                materialInfo.setMaterialCount(BigDecimal.ZERO); // 默认库存为0
                materialInfo.setMaxNum(excelVO.getMaxNum());
                materialInfo.setMinNum(excelVO.getMinNum());
                materialInfo.setShelfLife(excelVO.getShelfLife());
                materialInfo.setStatus(1); // 默认启用
                materialInfo.setTenantId(tenantId);
                materialInfoMapper.insert(materialInfo);
            }
            successCount++;
        }

        // 返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("successCount", successCount);
        result.put("errorCount", errorList.size());
        result.put("errorList", errorList);
        return result;
    }
}

