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

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yhy.module.core.enums.ErrorCodeConstants.BOQ_ITEM_TREE_CODE_DUPLICATE;
import static com.yhy.module.core.enums.ErrorCodeConstants.BOQ_ITEM_TREE_HAS_CHILDREN;
import static com.yhy.module.core.enums.ErrorCodeConstants.BOQ_ITEM_TREE_NOT_EXISTS;
import static com.yhy.module.core.enums.ErrorCodeConstants.BOQ_ITEM_TREE_NOT_SAME_LEVEL;
import static com.yhy.module.core.enums.ErrorCodeConstants.BOQ_ITEM_TREE_PARENT_NOT_EXISTS;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import com.yhy.module.core.controller.admin.boq.vo.BoqItemTreeDeleteCheckRespVO;
import com.yhy.module.core.controller.admin.boq.vo.BoqItemTreeRespVO;
import com.yhy.module.core.controller.admin.boq.vo.BoqItemTreeSaveReqVO;
import com.yhy.module.core.controller.admin.boq.vo.BoqItemTreeSwapSortReqVO;
import com.yhy.module.core.dal.dataobject.boq.BoqGuideTreeDO;
import com.yhy.module.core.dal.dataobject.boq.BoqItemTreeDO;
import com.yhy.module.core.dal.dataobject.boq.BoqSubItemDO;
import com.yhy.module.core.dal.mysql.boq.BoqGuideTreeMapper;
import com.yhy.module.core.dal.mysql.boq.BoqItemTreeMapper;
import com.yhy.module.core.dal.mysql.boq.BoqSubItemMapper;
import com.yhy.module.core.service.boq.BoqItemTreeService;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

/**
 * 清单项树 Service 实现类
 *
 * @author yhy
 */
@Service
@Validated
@Slf4j
public class BoqItemTreeServiceImpl implements BoqItemTreeService {

    @Resource
    private BoqItemTreeMapper boqItemTreeMapper;

    @Resource
    private BoqSubItemMapper boqSubItemMapper;

    @Resource
    private BoqGuideTreeMapper boqGuideTreeMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createBoqItemTree(BoqItemTreeSaveReqVO createReqVO) {
        // 1. 校验编码唯一性（如果编码不为空）
        if (createReqVO.getCode() != null && !createReqVO.getCode().isEmpty()) {
            validateCodeUnique(null, createReqVO.getCode());
        }

        // 2. 构建DO对象
        BoqItemTreeDO boqItemTree = buildBoqItemTreeDO(createReqVO);

        // 3. 设置排序
        if (boqItemTree.getSortOrder() == null) {
            boqItemTree.setSortOrder(getNextSortOrder(createReqVO.getParentId(), createReqVO.getBoqCatalogItemId()));
        }

        // 4. 预设level和临时path（为了满足NOT NULL约束）
        BoqItemTreeDO parent = null;
        if (createReqVO.getParentId() != null) {
            parent = boqItemTreeMapper.selectById(createReqVO.getParentId());
            if (parent == null) {
                throw exception(BOQ_ITEM_TREE_PARENT_NOT_EXISTS);
            }
            boqItemTree.setLevel(parent.getLevel() + 1);
            boqItemTree.setPath(parent.getPath());  // 临时用父路径
        } else {
            boqItemTree.setLevel(1);
            boqItemTree.setPath(new String[]{});  // 临时空数组
        }

        // 5. 插入数据库获取ID
        boqItemTreeMapper.insert(boqItemTree);

        // 6. 更新真实路径
        String[] realPath = parent == null 
            ? new String[]{boqItemTree.getId().toString()}
            : ArrayUtil.append(parent.getPath(), boqItemTree.getId().toString());
        boqItemTree.setPath(realPath);
        boqItemTreeMapper.updateById(boqItemTree);

        return boqItemTree.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBoqItemTree(BoqItemTreeSaveReqVO updateReqVO) {
        // 1. 校验节点存在
        validateBoqItemTreeExists(updateReqVO.getId());

        // 2. 校验编码唯一性（如果编码不为空）
        if (updateReqVO.getCode() != null && !updateReqVO.getCode().isEmpty()) {
            validateCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
        }

        // 3. 构建更新对象（只更新非空字段）
        BoqItemTreeDO updateObj = BoqItemTreeDO.builder()
                .id(updateReqVO.getId())
                .code(updateReqVO.getCode())
                .name(updateReqVO.getName())
                .unit(updateReqVO.getUnit())
                .description(updateReqVO.getDescription())
                .sortOrder(updateReqVO.getSortOrder())
                .attributes(updateReqVO.getAttributes())
                .build();

        // 4. 更新数据库
        boqItemTreeMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBoqItemTree(Long id) {
        // 1. 校验节点存在
        validateBoqItemTreeExists(id);

        // 2. 校验是否有子节点
        List<BoqItemTreeDO> children = boqItemTreeMapper.selectListByParentId(id);
        if (CollUtil.isNotEmpty(children)) {
            throw exception(BOQ_ITEM_TREE_HAS_CHILDREN);
        }

        // 3. 删除节点
        boqItemTreeMapper.deleteById(id);
    }

    @Override
    public BoqItemTreeRespVO getBoqItemTree(Long id) {
        BoqItemTreeDO item = boqItemTreeMapper.selectById(id);
        if (item == null) {
            return null;
        }
        return convertToRespVO(item);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<BoqItemTreeRespVO> getBoqItemTreeTree(Long boqCatalogItemId) {
        // 1. 查询所有节点
        List<BoqItemTreeDO> allItems = boqItemTreeMapper.selectListByBoqCatalogItemId(boqCatalogItemId);

        // 2. 查找所有parentId为null的节点
        List<BoqItemTreeDO> rootNodes = allItems.stream()
                .filter(item -> item.getParentId() == null)
                .sorted((a, b) -> {
                    Integer sortA = a.getSortOrder() != null ? a.getSortOrder() : Integer.MAX_VALUE;
                    Integer sortB = b.getSortOrder() != null ? b.getSortOrder() : Integer.MAX_VALUE;
                    return sortA.compareTo(sortB);
                })
                .collect(Collectors.toList());
        
        BoqItemTreeDO rootNode;
        
        // 3. 如果没有根节点，自动创建一个
        if (rootNodes.isEmpty()) {
            rootNode = BoqItemTreeDO.builder()
                    .boqCatalogItemId(boqCatalogItemId)
                    .parentId(null)
                    .code("")
                    .name("根目录")
                    .level(1)
                    .sortOrder(1)
                    .path(new String[]{})  // 临时空数组
                    .build();
            boqItemTreeMapper.insert(rootNode);
            
            // 更新真实路径
            rootNode.setPath(new String[]{rootNode.getId().toString()});
            boqItemTreeMapper.updateById(rootNode);
            
            // 添加到列表
            allItems.add(rootNode);
        } else {
            // 取sortOrder最小的作为根节点
            rootNode = rootNodes.get(0);
            
            // 4. 如果存在多个parentId为null的节点，将其他节点挂到根节点下
            if (rootNodes.size() > 1) {
                for (int i = 1; i < rootNodes.size(); i++) {
                    BoqItemTreeDO orphanNode = rootNodes.get(i);
                    orphanNode.setParentId(rootNode.getId());
                    orphanNode.setLevel(rootNode.getLevel() + 1);
                    // 更新路径
                    String[] newPath = ArrayUtil.append(rootNode.getPath(), orphanNode.getId().toString());
                    orphanNode.setPath(newPath);
                    boqItemTreeMapper.updateById(orphanNode);
                    
                    // 更新内存中的数据
                    allItems.stream()
                            .filter(item -> item.getId().equals(orphanNode.getId()))
                            .findFirst()
                            .ifPresent(item -> {
                                item.setParentId(rootNode.getId());
                                item.setLevel(orphanNode.getLevel());
                                item.setPath(newPath);
                            });
                }
            }
        }

        // 5. 转换为VO
        List<BoqItemTreeRespVO> allVOs = allItems.stream()
                .map(this::convertToRespVO)
                .collect(Collectors.toList());

        // 6. 构建树形结构
        return buildTree(allVOs, null);
    }

    @Override
    public List<BoqItemTreeRespVO> getBoqItemTreeList(Long boqCatalogItemId) {
        // 查询所有节点并转换为VO
        List<BoqItemTreeDO> items = boqItemTreeMapper.selectListByBoqCatalogItemId(boqCatalogItemId);
        return items.stream()
                .map(this::convertToRespVO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSort(BoqItemTreeSwapSortReqVO swapReqVO) {
        // 1. 查询两个节点（加锁）
        BoqItemTreeDO node1 = boqItemTreeMapper.selectById(swapReqVO.getNodeId1());
        BoqItemTreeDO node2 = boqItemTreeMapper.selectById(swapReqVO.getNodeId2());

        if (node1 == null || node2 == null) {
            throw exception(BOQ_ITEM_TREE_NOT_EXISTS);
        }

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

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

        // 4. 更新数据库
        boqItemTreeMapper.updateById(node1);
        boqItemTreeMapper.updateById(node2);

        log.info("[swapSort] 交换节点[{}]和节点[{}]的排序成功", swapReqVO.getNodeId1(), swapReqVO.getNodeId2());
    }

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

    /**
     * 校验编码唯一性
     */
    private void validateCodeUnique(Long id, String code) {
        BoqItemTreeDO existing = boqItemTreeMapper.selectByCode(code);
        if (existing != null && !existing.getId().equals(id)) {
            throw exception(BOQ_ITEM_TREE_CODE_DUPLICATE, code);
        }
    }

    /**
     * 校验节点存在
     */
    private BoqItemTreeDO validateBoqItemTreeExists(Long id) {
        BoqItemTreeDO item = boqItemTreeMapper.selectById(id);
        if (item == null) {
            throw exception(BOQ_ITEM_TREE_NOT_EXISTS);
        }
        return item;
    }

    /**
     * 构建DO对象
     */
    private BoqItemTreeDO buildBoqItemTreeDO(BoqItemTreeSaveReqVO reqVO) {
        return BoqItemTreeDO.builder()
                .id(reqVO.getId())
                .boqCatalogItemId(reqVO.getBoqCatalogItemId())
                .parentId(reqVO.getParentId())
                .code(reqVO.getCode() != null ? reqVO.getCode() : "")  // code不能为null
                .name(reqVO.getName())
                .unit(reqVO.getUnit() != null ? reqVO.getUnit() : "")  // unit不能为null
                .description(reqVO.getDescription())
                .sortOrder(reqVO.getSortOrder())
                .attributes(reqVO.getAttributes())
                .build();
    }

    /**
     * 获取下一个排序值
     */
    private Integer getNextSortOrder(Long parentId, Long boqCatalogItemId) {
        List<BoqItemTreeDO> siblings = boqItemTreeMapper.selectSiblings(parentId, boqCatalogItemId);
        if (CollUtil.isEmpty(siblings)) {
            return 1;
        }
        return siblings.stream()
                .mapToInt(BoqItemTreeDO::getSortOrder)
                .max()
                .orElse(0) + 1;
    }

    /**
     * 转换为RespVO
     */
    private BoqItemTreeRespVO convertToRespVO(BoqItemTreeDO item) {
        BoqItemTreeRespVO vo = new BoqItemTreeRespVO();
        vo.setId(item.getId());
        vo.setBoqCatalogItemId(item.getBoqCatalogItemId());
        vo.setParentId(item.getParentId());
        vo.setCode(item.getCode());
        vo.setName(item.getName());
        vo.setUnit(item.getUnit());
        vo.setDescription(item.getDescription());
        vo.setSortOrder(item.getSortOrder());
        vo.setPath(item.getPath());
        vo.setLevel(item.getLevel());
        vo.setAttributes(item.getAttributes());
        vo.setCreateTime(item.getCreateTime());
        vo.setUpdateTime(item.getUpdateTime());
        return vo;
    }

    /**
     * 构建树形结构
     */
    private List<BoqItemTreeRespVO> buildTree(List<BoqItemTreeRespVO> allNodes, Long parentId) {
        List<BoqItemTreeRespVO> result = new ArrayList<>();
        for (BoqItemTreeRespVO node : allNodes) {
            if ((parentId == null && node.getParentId() == null)
                    || (parentId != null && parentId.equals(node.getParentId()))) {
                node.setChildren(buildTree(allNodes, node.getId()));
                result.add(node);
            }
        }
        return result;
    }

    /**
     * 判断是否同级
     */
    private boolean isSameLevel(BoqItemTreeDO node1, BoqItemTreeDO node2) {
        // 父节点相同且清单专业相同即为同级
        if (!node1.getBoqCatalogItemId().equals(node2.getBoqCatalogItemId())) {
            return false;
        }
        if (node1.getParentId() == null && node2.getParentId() == null) {
            return true;
        }
        if (node1.getParentId() == null || node2.getParentId() == null) {
            return false;
        }
        return node1.getParentId().equals(node2.getParentId());
    }

    @Override
    public BoqItemTreeDeleteCheckRespVO checkDeleteBoqItemTree(Long id) {
        // 1. 校验节点存在
        validateBoqItemTreeExists(id);

        BoqItemTreeDeleteCheckRespVO result = new BoqItemTreeDeleteCheckRespVO();

        // 2. 检查子节点
        List<BoqItemTreeDO> children = boqItemTreeMapper.selectListByParentId(id);
        int childrenCount = children.size();
        result.setHasChildren(childrenCount > 0);
        result.setChildrenCount(childrenCount);

        // 3. 递归获取所有子孙节点ID（用于检查清单子目和指引）
        List<Long> allDescendantIds = new ArrayList<>();
        allDescendantIds.add(id);
        collectDescendantIds(id, allDescendantIds);

        // 4. 检查清单子目
        int subItemsCount = 0;
        for (Long nodeId : allDescendantIds) {
            List<BoqSubItemDO> subItems = boqSubItemMapper.selectListByBoqItemTreeId(nodeId);
            subItemsCount += subItems.size();
        }
        result.setHasSubItems(subItemsCount > 0);
        result.setSubItemsCount(subItemsCount);

        // 5. 检查清单指引（通过清单子目关联）
        int guidesCount = 0;
        for (Long nodeId : allDescendantIds) {
            List<BoqSubItemDO> subItems = boqSubItemMapper.selectListByBoqItemTreeId(nodeId);
            for (BoqSubItemDO subItem : subItems) {
                List<BoqGuideTreeDO> guides = boqGuideTreeMapper.selectListByBoqSubItemId(subItem.getId());
                guidesCount += guides.size();
            }
        }
        result.setHasGuides(guidesCount > 0);
        result.setGuidesCount(guidesCount);

        // 6. 判断是否可以直接删除
        boolean canDirectDelete = childrenCount == 0 && subItemsCount == 0 && guidesCount == 0;
        result.setCanDirectDelete(canDirectDelete);

        // 7. 生成确认提示信息
        if (canDirectDelete) {
            result.setConfirmMessage("确定要删除该节点吗？");
        } else {
            StringBuilder msg = new StringBuilder("该节点包含以下关联数据：\n");
            if (childrenCount > 0) {
                msg.append("- 子节点：").append(childrenCount).append(" 个\n");
            }
            if (subItemsCount > 0) {
                msg.append("- 清单子目：").append(subItemsCount).append(" 个\n");
            }
            if (guidesCount > 0) {
                msg.append("- 清单指引：").append(guidesCount).append(" 个\n");
            }
            msg.append("\n删除后将同时删除所有关联数据，确定要继续吗？");
            result.setConfirmMessage(msg.toString());
        }

        return result;
    }

    /**
     * 递归收集所有子孙节点ID
     */
    private void collectDescendantIds(Long parentId, List<Long> ids) {
        List<BoqItemTreeDO> children = boqItemTreeMapper.selectListByParentId(parentId);
        for (BoqItemTreeDO child : children) {
            ids.add(child.getId());
            collectDescendantIds(child.getId(), ids);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void forceDeleteBoqItemTree(Long id) {
        // 1. 校验节点存在
        validateBoqItemTreeExists(id);

        // 2. 递归获取所有子孙节点ID
        List<Long> allDescendantIds = new ArrayList<>();
        allDescendantIds.add(id);
        collectDescendantIds(id, allDescendantIds);

        // 3. 从叶子节点开始删除（逆序）
        for (int i = allDescendantIds.size() - 1; i >= 0; i--) {
            Long nodeId = allDescendantIds.get(i);
            
            // 3.1 删除该节点关联的清单指引
            List<BoqSubItemDO> subItems = boqSubItemMapper.selectListByBoqItemTreeId(nodeId);
            for (BoqSubItemDO subItem : subItems) {
                List<BoqGuideTreeDO> guides = boqGuideTreeMapper.selectListByBoqSubItemId(subItem.getId());
                for (BoqGuideTreeDO guide : guides) {
                    boqGuideTreeMapper.deleteById(guide.getId());
                }
            }
            
            // 3.2 删除该节点关联的清单子目
            for (BoqSubItemDO subItem : subItems) {
                boqSubItemMapper.deleteById(subItem.getId());
            }
            
            // 3.3 删除该节点
            boqItemTreeMapper.deleteById(nodeId);
        }
    }
}
