package cn.iocoder.yudao.module.server.service.materialcategory;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import cn.iocoder.yudao.module.server.controller.admin.materialcategory.vo.*;
import cn.iocoder.yudao.module.server.dal.dataobject.materialcategory.MaterialCategoryDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.server.dal.mysql.materialcategory.MaterialCategoryMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.server.enums.ErrorCodeConstants.*;

/**
 * 资料分类 Service 实现类
 *
 * @author TRS
 */
@Service
@Validated
public class MaterialCategoryServiceImpl implements MaterialCategoryService {

    @Resource
    private MaterialCategoryMapper materialCategoryMapper;

    @Override
    public Long createMaterialCategory(MaterialCategorySaveReqVO createReqVO) {
        // 校验父分类ID的有效性
        validateParentMaterialCategory(null, createReqVO.getParentId());
        // 校验分类名称的唯一性
        validateMaterialCategoryNameUnique(null, createReqVO.getParentId(), createReqVO.getName());

        // 插入
        MaterialCategoryDO materialCategory = BeanUtils.toBean(createReqVO, MaterialCategoryDO.class);
        materialCategoryMapper.insert(materialCategory);
        // 返回
        return materialCategory.getId();
    }

    @Override
    public void updateMaterialCategory(MaterialCategorySaveReqVO updateReqVO) {
        // 校验存在
        validateMaterialCategoryExists(updateReqVO.getId());
        // 校验父分类ID的有效性
        validateParentMaterialCategory(updateReqVO.getId(), updateReqVO.getParentId());
        // 校验分类名称的唯一性
        validateMaterialCategoryNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());

        // 更新
        MaterialCategoryDO updateObj = BeanUtils.toBean(updateReqVO, MaterialCategoryDO.class);
        materialCategoryMapper.updateById(updateObj);
    }

    @Override
    public void deleteMaterialCategory(Long id) {
        // 校验存在
        validateMaterialCategoryExists(id);
        // 校验是否有子资料分类
        if (materialCategoryMapper.selectCountByParentId(id) > 0) {
            throw exception(MATERIAL_CATEGORY_EXITS_CHILDREN);
        }
        // 删除
        materialCategoryMapper.deleteById(id);
    }

    private void validateMaterialCategoryExists(Long id) {
        if (materialCategoryMapper.selectById(id) == null) {
            throw exception(MATERIAL_CATEGORY_NOT_EXISTS);
        }
    }

    private void validateParentMaterialCategory(Long id, Long parentId) {
        if (parentId == null || MaterialCategoryDO.PARENT_ID_ROOT.equals(parentId)) {
            return;
        }
        // 1. 不能设置自己为父资料分类
        if (Objects.equals(id, parentId)) {
            throw exception(MATERIAL_CATEGORY_PARENT_ERROR);
        }
        // 2. 父资料分类不存在
        MaterialCategoryDO parentMaterialCategory = materialCategoryMapper.selectById(parentId);
        if (parentMaterialCategory == null) {
            throw exception(MATERIAL_CATEGORY_PARENT_NOT_EXITS);
        }
        // 3. 递归校验父资料分类，如果父资料分类是自己的子资料分类，则报错，避免形成环路
        if (id == null) { // id 为空，说明新增，不需要考虑环路
            return;
        }
        for (int i = 0; i < Short.MAX_VALUE; i++) {
            // 3.1 校验环路
            parentId = parentMaterialCategory.getParentId();
            if (Objects.equals(id, parentId)) {
                throw exception(MATERIAL_CATEGORY_PARENT_IS_CHILD);
            }
            // 3.2 继续递归下一级父资料分类
            if (parentId == null || MaterialCategoryDO.PARENT_ID_ROOT.equals(parentId)) {
                break;
            }
            parentMaterialCategory = materialCategoryMapper.selectById(parentId);
            if (parentMaterialCategory == null) {
                break;
            }
        }
    }

    private void validateMaterialCategoryNameUnique(Long id, Long parentId, String name) {
        MaterialCategoryDO materialCategory = materialCategoryMapper.selectByParentIdAndName(parentId, name);
        if (materialCategory == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的资料分类
        if (id == null) {
            throw exception(MATERIAL_CATEGORY_NAME_DUPLICATE);
        }
        if (!Objects.equals(materialCategory.getId(), id)) {
            throw exception(MATERIAL_CATEGORY_NAME_DUPLICATE);
        }
    }

    @Override
    public MaterialCategoryDO getMaterialCategory(Long id) {
        return materialCategoryMapper.selectById(id);
    }

    @Override
    public List<MaterialCategoryDO> getMaterialCategoryList(MaterialCategoryListReqVO listReqVO) {
        return materialCategoryMapper.selectList(listReqVO);
    }

    /**
     * 获取分类树
     */
    public List<MaterialCategoryDO> getCategoryTree() {
        // 查询所有启用的分类
        List<MaterialCategoryDO> allCategories = materialCategoryMapper.selectList();

        // 构建树形结构
        return buildTree(allCategories);
    }

    /**
     * 构建树形结构
     */
    private List<MaterialCategoryDO> buildTree(List<MaterialCategoryDO> allCategories) {
        // 存储顶级分类
        List<MaterialCategoryDO> rootCategories = new ArrayList<>();

        // 使用Map存储所有分类，key为分类ID
        Map<Long, MaterialCategoryDO> categoryMap = new HashMap<>();
        for (MaterialCategoryDO category : allCategories) {
            category.setChildren(new ArrayList<>());
            categoryMap.put(category.getId(), category);
        }

        // 遍历所有分类，构建父子关系
        for (MaterialCategoryDO category : allCategories) {
            if (category.getParentId() == null || category.getParentId() == 0L) {
                // 顶级分类
                rootCategories.add(category);
            } else {
                // 子分类，添加到父分类的children中
                MaterialCategoryDO parent = categoryMap.get(category.getParentId());
                if (parent != null) {
                    parent.getChildren().add(category);
                }
            }
        }

        // 对每个层级的分类进行排序
        sortCategories(rootCategories);

        return rootCategories;
    }

    /**
     * 递归排序分类
     */
    private void sortCategories(List<MaterialCategoryDO> categories) {
        if (CollectionUtils.isEmpty(categories)) {
            return;
        }

        // 按sort字段升序排序
        categories.sort(Comparator.comparingInt(MaterialCategoryDO::getSort));

        // 递归排序子分类
        for (MaterialCategoryDO category : categories) {
            sortCategories(category.getChildren());
        }
    }

}