package com.yhy.module.core.service.infoprice.impl;

import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import com.yhy.module.core.controller.admin.infoprice.vo.InfoPriceCategoryTreeRespVO;
import com.yhy.module.core.controller.admin.infoprice.vo.InfoPriceCategoryTreeSaveReqVO;
import com.yhy.module.core.controller.admin.infoprice.vo.InfoPriceCategoryTreeSwapSortReqVO;
import com.yhy.module.core.dal.dataobject.infoprice.InfoPriceCategoryTreeDO;
import com.yhy.module.core.dal.mysql.infoprice.InfoPriceCategoryTreeMapper;
import com.yhy.module.core.dal.mysql.infoprice.InfoPriceResourceMapper;
import com.yhy.module.core.enums.infoprice.InfoPriceCategoryNodeTypeEnum;
import com.yhy.module.core.service.infoprice.InfoPriceCategoryTreeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
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 com.yhy.module.core.enums.ErrorCodeConstants.*;

/**
 * 信息价分类树 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class InfoPriceCategoryTreeServiceImpl implements InfoPriceCategoryTreeService {

    @Resource
    private InfoPriceCategoryTreeMapper categoryTreeMapper;

    @Resource
    private InfoPriceResourceMapper resourceMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createCategoryTree(InfoPriceCategoryTreeSaveReqVO createReqVO) {
        // 1. 校验节点类型
        validateNodeType(createReqVO.getNodeType());

        // 2. 校验父节点
        InfoPriceCategoryTreeDO parent = null;
        if (createReqVO.getParentId() != null) {
            parent = validateParentExists(createReqVO.getParentId());
            // 内容节点不能添加子节点
            if (InfoPriceCategoryNodeTypeEnum.CONTENT.getType().equals(parent.getNodeType())) {
                throw exception(INFO_PRICE_CATEGORY_TREE_CONTENT_NO_CHILDREN);
            }
        }

        // 3. 校验编码唯一性
        validateCodeUnique(createReqVO.getBookId(), createReqVO.getParentId(), createReqVO.getCode(), null);

        // 4. 插入
        InfoPriceCategoryTreeDO categoryTree = BeanUtils.toBean(createReqVO, InfoPriceCategoryTreeDO.class);
        
        // 计算路径
        if (parent != null) {
            String[] parentPath = parent.getPath();
            String[] newPath = Arrays.copyOf(parentPath, parentPath.length + 1);
            newPath[parentPath.length] = parent.getId().toString();
            categoryTree.setPath(newPath);
        } else {
            categoryTree.setPath(new String[0]);
        }

        // 计算排序
        List<InfoPriceCategoryTreeDO> siblings = categoryTreeMapper.selectListByParentId(
                createReqVO.getBookId(), createReqVO.getParentId());
        categoryTree.setSortOrder(siblings.size() + 1);

        categoryTreeMapper.insert(categoryTree);
        return categoryTree.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCategoryTree(InfoPriceCategoryTreeSaveReqVO updateReqVO) {
        // 1. 校验存在
        InfoPriceCategoryTreeDO categoryTree = validateCategoryTreeExists(updateReqVO.getId());

        // 2. 校验节点类型
        validateNodeType(updateReqVO.getNodeType());

        // 3. 校验编码唯一性
        validateCodeUnique(categoryTree.getBookId(), categoryTree.getParentId(), 
                updateReqVO.getCode(), updateReqVO.getId());

        // 4. 更新
        InfoPriceCategoryTreeDO updateObj = BeanUtils.toBean(updateReqVO, InfoPriceCategoryTreeDO.class);
        categoryTreeMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCategoryTree(Long id) {
        // 1. 校验存在
        validateCategoryTreeExists(id);

        // 2. 校验是否有子节点
        List<InfoPriceCategoryTreeDO> children = categoryTreeMapper.selectList(
                "parent_id", id);
        if (!children.isEmpty()) {
            throw exception(INFO_PRICE_CATEGORY_TREE_HAS_CHILDREN);
        }

        // 3. 校验是否有工料机信息
        long resourceCount = resourceMapper.selectCount("category_tree_id", id);
        if (resourceCount > 0) {
            throw exception(INFO_PRICE_CATEGORY_TREE_HAS_RESOURCES);
        }

        // 4. 删除
        categoryTreeMapper.deleteById(id);
    }

    @Override
    public InfoPriceCategoryTreeRespVO getCategoryTree(Long id) {
        InfoPriceCategoryTreeDO categoryTree = categoryTreeMapper.selectById(id);
        if (categoryTree == null) {
            return null;
        }
        return convertToRespVO(categoryTree);
    }

    @Override
    public List<InfoPriceCategoryTreeRespVO> getCategoryTreeList(Long bookId) {
        List<InfoPriceCategoryTreeDO> list = categoryTreeMapper.selectListByBookId(bookId);
        return BeanUtils.toBean(list, InfoPriceCategoryTreeRespVO.class);
    }

    @Override
    public List<InfoPriceCategoryTreeRespVO> getCategoryTreeTree(Long bookId) {
        List<InfoPriceCategoryTreeDO> list = categoryTreeMapper.selectListByBookId(bookId);
        return buildTree(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSort(InfoPriceCategoryTreeSwapSortReqVO reqVO) {
        // 1. 校验节点存在
        InfoPriceCategoryTreeDO node1 = validateCategoryTreeExists(reqVO.getNodeId1());
        InfoPriceCategoryTreeDO node2 = validateCategoryTreeExists(reqVO.getNodeId2());

        // 2. 校验是否同级
        if (!isSameLevel(node1, node2)) {
            throw exception(INFO_PRICE_CATEGORY_TREE_NOT_SAME_LEVEL);
        }

        // 3. 交换排序
        Integer tempSort = node1.getSortOrder();
        node1.setSortOrder(node2.getSortOrder());
        node2.setSortOrder(tempSort);

        categoryTreeMapper.updateById(node1);
        categoryTreeMapper.updateById(node2);
    }

    // ==================== 私有方法 ====================

    private InfoPriceCategoryTreeDO validateCategoryTreeExists(Long id) {
        InfoPriceCategoryTreeDO categoryTree = categoryTreeMapper.selectById(id);
        if (categoryTree == null) {
            throw exception(INFO_PRICE_CATEGORY_TREE_NOT_EXISTS);
        }
        return categoryTree;
    }

    private InfoPriceCategoryTreeDO validateParentExists(Long parentId) {
        InfoPriceCategoryTreeDO parent = categoryTreeMapper.selectById(parentId);
        if (parent == null) {
            throw exception(INFO_PRICE_CATEGORY_TREE_PARENT_NOT_EXISTS);
        }
        return parent;
    }

    private void validateNodeType(Integer nodeType) {
        InfoPriceCategoryNodeTypeEnum nodeTypeEnum = InfoPriceCategoryNodeTypeEnum.valueOfType(nodeType);
        if (nodeTypeEnum == null) {
            throw exception(INFO_PRICE_CATEGORY_TREE_INVALID_NODE_TYPE);
        }
    }

    private void validateCodeUnique(Long bookId, Long parentId, String code, Long excludeId) {
        InfoPriceCategoryTreeDO existing = categoryTreeMapper.selectByBookIdAndCode(bookId, parentId, code);
        if (existing != null && !existing.getId().equals(excludeId)) {
            throw exception(INFO_PRICE_CATEGORY_TREE_CODE_DUPLICATE, code);
        }
    }

    private boolean isSameLevel(InfoPriceCategoryTreeDO node1, InfoPriceCategoryTreeDO node2) {
        if (node1.getParentId() == null && node2.getParentId() == null) {
            return true;
        }
        if (node1.getParentId() != null && node2.getParentId() != null) {
            return node1.getParentId().equals(node2.getParentId());
        }
        return false;
    }

    private InfoPriceCategoryTreeRespVO convertToRespVO(InfoPriceCategoryTreeDO categoryTree) {
        InfoPriceCategoryTreeRespVO respVO = BeanUtils.toBean(categoryTree, InfoPriceCategoryTreeRespVO.class);
        // 设置节点类型名称
        InfoPriceCategoryNodeTypeEnum nodeTypeEnum = InfoPriceCategoryNodeTypeEnum.valueOfType(categoryTree.getNodeType());
        if (nodeTypeEnum != null) {
            respVO.setNodeTypeName(nodeTypeEnum.getName());
        }
        return respVO;
    }

    private List<InfoPriceCategoryTreeRespVO> buildTree(List<InfoPriceCategoryTreeDO> list) {
        if (list.isEmpty()) {
            return new ArrayList<>();
        }

        // 转换为 VO
        List<InfoPriceCategoryTreeRespVO> voList = list.stream()
                .map(this::convertToRespVO)
                .collect(Collectors.toList());

        // 构建 Map
        Map<Long, InfoPriceCategoryTreeRespVO> map = voList.stream()
                .collect(Collectors.toMap(InfoPriceCategoryTreeRespVO::getId, v -> v));

        // 构建树
        List<InfoPriceCategoryTreeRespVO> tree = new ArrayList<>();
        for (InfoPriceCategoryTreeRespVO vo : voList) {
            if (vo.getParentId() == null) {
                tree.add(vo);
            } else {
                InfoPriceCategoryTreeRespVO parent = map.get(vo.getParentId());
                if (parent != null) {
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>());
                    }
                    parent.getChildren().add(vo);
                }
            }
        }

        return tree;
    }

}
