package com.zt.plat.module.base.service.materialclasses;

import cn.hutool.core.collection.CollUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import com.zt.plat.module.base.controller.admin.materialclasses.vo.*;
import com.zt.plat.module.base.dal.dataobject.materialclasses.MaterialClassesDO;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;

import com.zt.plat.module.base.dal.dao.materialclasses.MaterialClassesMapper;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.base.enums.ErrorCodeConstants.*;

/**
 * 物料分类 Service 实现类
 *
 * @author 后台管理-1
 */
@Service
@Validated
public class MaterialClassesServiceImpl implements MaterialClassesService {

    @Resource
    private MaterialClassesMapper materialClassesMapper;

    private static final int MAX_LEVEL = 3;

    @Override
    public MaterialClassesRespVO createMaterialClasses(MaterialClassesSaveReqVO createReqVO) {
        Long normalizedParentId = normalizeParentId(createReqVO.getParentId());
        MaterialClassesDO parent = validateAndGetParent(null, normalizedParentId);
        long resolvedLevel = resolveLevel(parent);
        validateLevel(resolvedLevel);
        if (createReqVO.getLevel() != null && !Objects.equals(createReqVO.getLevel(), resolvedLevel)) {
            throw exception(MATERIAL_CLASSES_HIERARCHY_INVALID);
        }
        // 插入
        MaterialClassesDO materialClasses = BeanUtils.toBean(createReqVO, MaterialClassesDO.class);
        materialClasses.setParentId(normalizedParentId);
        materialClasses.setLevel(resolvedLevel);
        materialClassesMapper.insert(materialClasses);
        // 返回
        return BeanUtils.toBean(materialClasses, MaterialClassesRespVO.class);
    }

    @Override
    public void updateMaterialClasses(MaterialClassesSaveReqVO updateReqVO) {
        // 校验存在
        validateMaterialClassesExists(updateReqVO.getId());
        Long normalizedParentId = normalizeParentId(updateReqVO.getParentId());
        MaterialClassesDO parent = validateAndGetParent(updateReqVO.getId(), normalizedParentId);
        long resolvedLevel = resolveLevel(parent);
        validateLevel(resolvedLevel);
        if (updateReqVO.getLevel() != null && !Objects.equals(updateReqVO.getLevel(), resolvedLevel)) {
            throw exception(MATERIAL_CLASSES_HIERARCHY_INVALID);
        }
        ensureChildrenCompatible(updateReqVO.getId(), resolvedLevel);
        // 更新
        MaterialClassesDO updateObj = BeanUtils.toBean(updateReqVO, MaterialClassesDO.class);
        updateObj.setParentId(normalizedParentId);
        updateObj.setLevel(resolvedLevel);
        materialClassesMapper.updateById(updateObj);
    }

    @Override
    public void deleteMaterialClasses(Long id) {
        // 校验存在
        validateMaterialClassesExists(id);
        // 删除
        materialClassesMapper.deleteById(id);
    }

    @Override
        public void deleteMaterialClassesListByIds(List<Long> ids) {
        // 校验存在
        validateMaterialClassesExists(ids);
        // 删除
        materialClassesMapper.deleteByIds(ids);
        }

    private void validateMaterialClassesExists(List<Long> ids) {
        List<MaterialClassesDO> list = materialClassesMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(MATERIAL_CLASSES_NOT_EXISTS);
        }
    }

    private void validateMaterialClassesExists(Long id) {
        if (materialClassesMapper.selectById(id) == null) {
            throw exception(MATERIAL_CLASSES_NOT_EXISTS);
        }
    }

    @Override
    public MaterialClassesDO getMaterialClasses(Long id) {
        return materialClassesMapper.selectById(id);
    }

    @Override
    public PageResult<MaterialClassesDO> getMaterialClassesPage(MaterialClassesPageReqVO pageReqVO) {
        return materialClassesMapper.selectPage(pageReqVO);
    }

    @Override
    public List<MaterialClassesDO> getMaterialClassesList() {
        return materialClassesMapper.selectList();
    }

    private Long normalizeParentId(Long parentId) {
        if (parentId == null || parentId <= 0) {
            return null;
        }
        return parentId;
    }

    private MaterialClassesDO validateAndGetParent(Long currentId, Long parentId) {
        if (parentId == null) {
            return null;
        }
        if (currentId != null && Objects.equals(currentId, parentId)) {
            throw exception(MATERIAL_CLASSES_HIERARCHY_INVALID);
        }
        MaterialClassesDO parent = materialClassesMapper.selectById(parentId);
        if (parent == null) {
            throw exception(MATERIAL_CLASSES_PARENT_NOT_EXISTS);
        }
        if (parent.getLevel() == null) {
            throw exception(MATERIAL_CLASSES_HIERARCHY_INVALID);
        }
        if (parent.getLevel() >= MAX_LEVEL) {
            throw exception(MATERIAL_CLASSES_MAX_LEVEL_EXCEEDED);
        }
        if (currentId != null) {
            Long cursorId = parent.getParentId();
            while (cursorId != null && cursorId > 0) {
                if (Objects.equals(cursorId, currentId)) {
                    throw exception(MATERIAL_CLASSES_HIERARCHY_INVALID);
                }
                MaterialClassesDO cursor = materialClassesMapper.selectById(cursorId);
                if (cursor == null) {
                    break;
                }
                cursorId = cursor.getParentId();
            }
        }
        return parent;
    }

    private long resolveLevel(MaterialClassesDO parent) {
        if (parent == null) {
            return 1L;
        }
        Long parentLevel = parent.getLevel();
        if (parentLevel == null) {
            throw exception(MATERIAL_CLASSES_HIERARCHY_INVALID);
        }
        return parentLevel + 1;
    }

    private void validateLevel(long level) {
        if (level < 1L) {
            throw exception(MATERIAL_CLASSES_HIERARCHY_INVALID);
        }
        if (level > MAX_LEVEL) {
            throw exception(MATERIAL_CLASSES_MAX_LEVEL_EXCEEDED);
        }
    }

    private void ensureChildrenCompatible(Long currentId, long level) {
        List<MaterialClassesDO> children = materialClassesMapper.selectList(MaterialClassesDO::getParentId, currentId);
        if (CollUtil.isEmpty(children)) {
            return;
        }
        long expectedChildLevel = level + 1;
        if (expectedChildLevel > MAX_LEVEL) {
            throw exception(MATERIAL_CLASSES_LEVEL_CONFLICT_WITH_CHILDREN);
        }
        boolean mismatch = children.stream()
                .anyMatch(child -> child.getLevel() == null || !Objects.equals(child.getLevel(), expectedChildLevel));
        if (mismatch) {
            throw exception(MATERIAL_CLASSES_HIERARCHY_INVALID);
        }
    }

}