package cn.iocoder.yudao.module.erp.service.product;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductImportExcelVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductImportRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPageReqVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductCategoryMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper;
import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper;
import cn.iocoder.yudao.module.erp.service.stock.ErpStockService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.ConstraintViolationException;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*;

/**
 * ERP 产品 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class ErpProductServiceImpl implements ErpProductService {

    @Resource
    private ErpProductMapper productMapper;

    @Resource
    private ErpProductCategoryMapper productCategoryMapper;

    @Resource
    private ErpProductCategoryService productCategoryService;
    @Resource
    private ErpProductUnitService productUnitService;

    @Resource
    private ErpStockMapper erpStockMapper;

    @Resource
    @Lazy  // 延迟注入
    private ErpStockService erpStockService;



    @Override
    public Long createProduct(ProductSaveReqVO createReqVO) {
        // TODO 芋艿：校验分类
        // 插入
        ErpProductDO product = BeanUtils.toBean(createReqVO, ErpProductDO.class);
        ErpProductCategoryDO productCategory = productCategoryMapper.selectById(product.getCategoryId());
        Long id = productCategory.getParentId();
        product.setSubCategoryName(productCategory.getName());
        product.setSubCategoryId(product.getCategoryId());
        while(id != 0) {
            productCategory = productCategoryMapper.selectById(id);
            product.setCategoryId(id);
            id = productCategory.getParentId();
        }
        productMapper.insert(product);
        // 返回
        return product.getId();
    }

    @Override
    public void updateProduct(ProductSaveReqVO updateReqVO) {
        // TODO 芋艿：校验分类
        // 校验存在
        validateProductExists(updateReqVO.getId());
        // 更新
        ErpProductDO updateObj = BeanUtils.toBean(updateReqVO, ErpProductDO.class);
        ErpProductCategoryDO productCategory = productCategoryMapper.selectById(updateObj.getCategoryId());
        Long id = productCategory.getParentId();
        updateObj.setSubCategoryName(productCategory.getName());
        updateObj.setSubCategoryId(updateObj.getCategoryId());
        while(id != 0) {
            productCategory = productCategoryMapper.selectById(id);
            updateObj.setCategoryId(id);
            id = productCategory.getParentId();
        }
        productMapper.updateById(updateObj);
    }

    @Override
    public void deleteProduct(Long id) {
        // 校验存在
        validateProductExists(id);

        //throw exception(PRODUCT_REFERENCES_EXIST);

        ErpProductDO erpProductDO =  productMapper.selectById(id);
        List<ErpStockDO> list = erpStockService.getStockByProductId(erpProductDO.getId());
        if(list != null && !list.isEmpty()){
            for(ErpStockDO erpStockDO : list){
                erpStockMapper.deleteById(erpStockDO.getId());
            }
        }
        // 删除
        productMapper.deleteById(id);
    }

    @Override
    public List<ErpProductDO> validProductList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<ErpProductDO> list = productMapper.selectBatchIds(ids);
        Map<Long, ErpProductDO> productMap = convertMap(list, ErpProductDO::getId);
        for (Long id : ids) {
            ErpProductDO product = productMap.get(id);
            if (productMap.get(id) == null) {
                throw exception(PRODUCT_NOT_EXISTS);
            }
            if (CommonStatusEnum.isDisable(product.getStatus())) {
                throw exception(PRODUCT_NOT_ENABLE, product.getName());
            }
        }
        return list;
    }

    private void validateProductExists(Long id) {
        if (productMapper.selectById(id) == null) {
            throw exception(PRODUCT_NOT_EXISTS);
        }
    }

    @Override
    public ErpProductDO getProduct(Long id) {
        return productMapper.selectById(id);
    }

    @Override
    public List<ErpProductRespVO> getProductVOListByStatus(Integer status) {
        List<ErpProductDO> list = productMapper.selectListByStatus(status);
        return buildProductVOList(list);
    }
    @Override
    public List<ErpProductRespVO> getProductVOListByCategory(Integer categoryId) {
        List<ErpProductDO> list = productMapper.selectListByCategoryId(categoryId);
        return buildProductVOList(list);
    }

    @Override
    public List<ErpProductRespVO> getProductVOList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<ErpProductDO> list = productMapper.selectBatchIds(ids);
        return buildProductVOList(list);
    }

    @Override
    public PageResult<ErpProductRespVO> getProductVOPage(ErpProductPageReqVO pageReqVO) {
        PageResult<ErpProductDO> pageResult = productMapper.selectPage(pageReqVO);
        return new PageResult<>(buildProductVOList(pageResult.getList()), pageResult.getTotal());
    }
    @Override
    public List<ErpProductRespVO> buildProductVOList(List<ErpProductDO> list) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }
        Map<Long, ErpProductCategoryDO> categoryMap = productCategoryService.getProductCategoryMap(
                convertSet(list, ErpProductDO::getCategoryId));
        Map<Long, ErpProductCategoryDO> subCategoryMap = productCategoryService.getProductCategoryMap(
                convertSet(list, ErpProductDO::getSubCategoryId));
        Map<Long, ErpProductUnitDO> unitMap = productUnitService.getProductUnitMap(
                convertSet(list, ErpProductDO::getUnitId));
        return BeanUtils.toBean(list, ErpProductRespVO.class, product -> {
            MapUtils.findAndThen(categoryMap, product.getCategoryId(),
                    category -> product.setCategoryName(category.getName()));
            MapUtils.findAndThen(subCategoryMap, product.getSubCategoryId(),
                    subCategory -> product.setSubCategoryName(subCategory.getName()));
            MapUtils.findAndThen(unitMap, product.getUnitId(),
                    unit -> product.setUnitName(unit.getName()));
        });
    }

    @Override
    public Long getProductCountByCategoryId(Long categoryId) {
        return productMapper.selectCountByCategoryId(categoryId);
    }

    @Override
    public Long getProductCountByUnitId(Long unitId) {
        return productMapper.selectCountByUnitId(unitId);
    }
    @Override
    public List<ErpProductDO> getProductList(Collection<Long> ids) {
        return productMapper.selectBatchIds(ids);
    }
    @Override
    public
    List<ErpProductDO> selectByCategorys(List<Integer> categoryIds){
        return productMapper.selectByCategorys(categoryIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ErpProductImportRespVO importProductList(List<ErpProductImportExcelVO> importProducts, boolean isUpdateSupport) {
        // 1. 参数校验
        if (CollUtil.isEmpty(importProducts)) {
            throw exception(PRODUCT_NOT_EXISTS);
        }

        // 2. 初始化返回结果
        ErpProductImportRespVO respVO = ErpProductImportRespVO.builder()
                .createNames(new ArrayList<>())
                .updateNames(new ArrayList<>())
                .failureNames(new LinkedHashMap<>())
                .build();

        // 3. 检查Excel中是否有重复的产品名称
        Set<String> excelNames = new HashSet<>();
        Set<String> duplicateNamesInExcel = new HashSet<>();
        for (ErpProductImportExcelVO importProduct : importProducts) {
            if (!excelNames.add(importProduct.getName())) {
                duplicateNamesInExcel.add(importProduct.getName());
            }
        }
        
        // 记录Excel中重复的产品名称
        for (String duplicateName : duplicateNamesInExcel) {
            respVO.getFailureNames().put(duplicateName, "Excel中存在重复的产品名称: " + duplicateName);
        }

        // 4. 获取数据库中已存在的产品
        Set<String> uniqueNamesToCheck = new HashSet<>(excelNames);
        uniqueNamesToCheck.removeAll(duplicateNamesInExcel); // 排除Excel中的重复项
        
        List<ErpProductDO> existingProducts = new ArrayList<>();
        if (!uniqueNamesToCheck.isEmpty()) {
            existingProducts = productMapper.selectListByNameIn(uniqueNamesToCheck);
        }
        
        Map<String, ErpProductDO> existingProductMap = existingProducts.stream()
                .collect(Collectors.toMap(ErpProductDO::getName, item -> item));

        // 5. 遍历导入数据
        for (ErpProductImportExcelVO importProduct : importProducts) {
            // 如果已在失败列表中，则跳过
            if (respVO.getFailureNames().containsKey(importProduct.getName())) {
                continue;
            }
            
            try {
                // 5.1 先处理分类和单位ID，确保它们被设置
                ErpProductDO productDOForConversion = convertToProductDO(importProduct);
                
                // 5.2 转换为保存对象
                ProductSaveReqVO saveReqVO = BeanUtils.toBean(importProduct, ProductSaveReqVO.class);
                
                // 5.3 设置saveReqVO中的ID值，以通过验证
                saveReqVO.setCategoryId(productDOForConversion.getCategoryId());
                saveReqVO.setUnitId(productDOForConversion.getUnitId());
                
                // 5.4 字段校验
                ValidationUtils.validate(saveReqVO);
            } catch (ConstraintViolationException ex) {
                respVO.getFailureNames().put(importProduct.getName(), ex.getMessage());
                continue;
            }

            // 5.2 检查是否已存在
            ErpProductDO existProduct = existingProductMap.get(importProduct.getName());
            if (existProduct == null) {
                try {
                    // 5.3 创建新记录
                    ErpProductDO newProduct = convertToProductDO(importProduct);
                    // 设置创建时间为当前时间
                    newProduct.setCreateTime(LocalDateTime.now());
                    productMapper.insert(newProduct);
                    respVO.getCreateNames().add(importProduct.getName());
                } catch (DuplicateKeyException e) {
                    // 处理并发插入或其他原因导致的重复键异常
                    respVO.getFailureNames().put(importProduct.getName(), "该产品已存在");
                }
            } else if (isUpdateSupport) {
                // 5.4 更新已有记录
                ErpProductDO updateProduct = convertToProductDO(importProduct);
                updateProduct.setId(existProduct.getId());
                // 保持原有创建时间不变
                updateProduct.setCreateTime(existProduct.getCreateTime());
                productMapper.updateById(updateProduct);
                respVO.getUpdateNames().add(importProduct.getName());
            } else {
                // 5.5 已存在且不支持更新
                respVO.getFailureNames().put(importProduct.getName(), "该产品已存在");
            }
        }

        return respVO;
    }

    private ErpProductDO convertToProductDO(ErpProductImportExcelVO importProduct) {
        ErpProductDO productDO = BeanUtils.toBean(importProduct, ErpProductDO.class);

        // 直接设置分类ID为5
        productDO.setCategoryId(5L);

        // 设置固定子分类名称为"备件"
        productDO.setSubCategoryName("备件");
        // 查找对应的子分类ID
        ErpProductCategoryDO subCategoryDO = productCategoryService.getProductCategoryByName("备件");
        if (subCategoryDO != null) {
            productDO.setSubCategoryId(subCategoryDO.getId());
        }

        // 处理单位名称
        if (StrUtil.isNotBlank(importProduct.getUnitName())) {
            ErpProductUnitDO unitDO = productUnitService.getProductUnitByName(importProduct.getUnitName());
            if (unitDO != null) {
                productDO.setUnitId(unitDO.getId());
            }
        }

        return productDO;
    }
}