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

import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;

import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yhy.module.core.controller.admin.resource.vo.CatalogItemSaveReqVO;
import com.yhy.module.core.controller.admin.resource.vo.ResourceCatalogItemTreeNodeVO;
import com.yhy.module.core.controller.admin.resource.vo.ResourceCategorySimpleRespVO;
import com.yhy.module.core.dal.dataobject.resource.ResourceCatalogItemDO;
import com.yhy.module.core.dal.mysql.resource.ResourceCatalogItemMapper;
import com.yhy.module.core.service.resource.ResourceCatalogItemService;
import com.yhy.module.core.service.resource.ResourceCategoryTreeService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

@Service
public class ResourceCatalogItemServiceImpl implements ResourceCatalogItemService {

    @Resource
    private ResourceCatalogItemMapper catalogItemMapper;
    
    @Resource
    private ResourceCategoryTreeService categoryTreeService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(CatalogItemSaveReqVO reqVO) {
        // 验证机类树节点是否存在（可选，根据业务需求决定是否需要）
        // ResourceCategoryTreeDO categoryTree = categoryTreeMapper.selectById(reqVO.getCategoryTreeId());
        // if (categoryTree == null) {
        //     throw exception0(BAD_REQUEST.getCode(), "工料机机类树节点不存在");
        // }
        Long tenantId = TenantContextHolder.getTenantId();
        checkCodeUnique(tenantId, reqVO.getCategoryTreeId(), reqVO.getCode(), null);

        // 如果是根节点（parentId 为 null），检查是否已存在根节点
        if (reqVO.getParentId() == null) {
            checkRootNodeUnique(tenantId, reqVO.getCategoryTreeId());
        }

        // 如果提供了 parentId，自动查询父路径
        List<String> parentPath = reqVO.getParentPath();
        if (reqVO.getParentId() != null) {
            ResourceCatalogItemDO parent = catalogItemMapper.selectById(reqVO.getParentId());
            if (parent == null) {
                throw exception0(BAD_REQUEST.getCode(), "父节点不存在");
            }
            // 使用父节点的完整路径作为 parentPath
            parentPath = parent.getPath() != null ? java.util.Arrays.asList(parent.getPath()) : new ArrayList<>();
        }

        ResourceCatalogItemDO item = BeanUtils.toBean(reqVO, ResourceCatalogItemDO.class);
        item.setTenantId(tenantId);
        item.setSortOrder(null); // 初始不设置排序号
        // 先设置一个临时的 path（空数组），插入后再更新
        item.setPath(new String[0]);
        catalogItemMapper.insert(item);
        
        // 插入后获得 id，使用 id 构建 path
        List<String> parentPathIds = parentPath;
        String[] finalPath = buildPath(parentPathIds, String.valueOf(item.getId()));
        item.setPath(finalPath);
        // 设置一个较大的 sortOrder，确保 reorderSiblings 时新节点排在最后（数据库默认值为0会导致排到第一位）
        item.setSortOrder(Integer.MAX_VALUE);
        catalogItemMapper.updateById(item);
        
        // 处理排序
        if (reqVO.getReferenceNodeId() != null && reqVO.getInsertPosition() != null) {
            insertNodeAtPosition(item, reqVO.getReferenceNodeId(), reqVO.getInsertPosition());
        } else {
            reorderSiblings(item.getCategoryTreeId(), item.getPath());
        }
        
        return item.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(CatalogItemSaveReqVO reqVO) {
        ResourceCatalogItemDO dbItem = catalogItemMapper.selectById(reqVO.getId());
        if (dbItem == null) {
            throw exception0(BAD_REQUEST.getCode(), "条目不存在");
        }
        Long tenantId = TenantContextHolder.getTenantId();
        checkCodeUnique(tenantId, dbItem.getCategoryTreeId(), reqVO.getCode(), dbItem.getId());

        // 如果提供了 parentId，自动查询父路径
        List<String> parentPath = reqVO.getParentPath();
        if (reqVO.getParentId() != null) {
            ResourceCatalogItemDO parent = catalogItemMapper.selectById(reqVO.getParentId());
            if (parent == null) {
                throw exception0(BAD_REQUEST.getCode(), "父节点不存在");
            }
            // 使用父节点的完整路径作为 parentPath
            parentPath = parent.getPath() != null ? java.util.Arrays.asList(parent.getPath()) : new ArrayList<>();
        }

        ResourceCatalogItemDO item = BeanUtils.toBean(reqVO, ResourceCatalogItemDO.class);
        item.setTenantId(tenantId);
        
        // 如果既没有提供 parentId 也没有提供 parentPath，保持原有的 path 不变
        if (reqVO.getParentId() == null && (reqVO.getParentPath() == null || reqVO.getParentPath().isEmpty())) {
            // 保持原有的 path 不变（path 存储的是 id，不需要更新）
            item.setPath(dbItem.getPath());
        } else {
            // 有提供 parentId 或 parentPath，重新构建 path（使用当前节点的 id）
            item.setPath(buildPath(parentPath, String.valueOf(reqVO.getId())));
        }
        
        catalogItemMapper.updateById(item);
    }

    @Override
    public void delete(Long id) {
        ResourceCatalogItemDO dbItem = catalogItemMapper.selectById(id);
        if (dbItem == null) {
            return;
        }
        // 检查是否有子节点
        Long count = catalogItemMapper.countChildNodes(
                dbItem.getCategoryTreeId(), 
                dbItem.getPath(), 
                TenantContextHolder.getTenantId()
        );
        if (count != null && count > 0) {
            throw exception0(BAD_REQUEST.getCode(), "存在子节点，不可删除");
        }
        catalogItemMapper.deleteById(id);
    }

    @Override
    public List<ResourceCatalogItemDO> listByCatalog(Long catalogId) {
        return catalogItemMapper.selectList(new LambdaQueryWrapper<ResourceCatalogItemDO>()
                .eq(ResourceCatalogItemDO::getCategoryTreeId, catalogId)
                .eq(ResourceCatalogItemDO::getTenantId, TenantContextHolder.getTenantId())
                .orderByAsc(ResourceCatalogItemDO::getPath)
                .orderByAsc(ResourceCatalogItemDO::getSortOrder));
    }
    
    @Override
    public List<ResourceCatalogItemTreeNodeVO> getTreeByCatalog(Long catalogId) {
        // 1. 查询所有节点（按path排序）
        List<ResourceCatalogItemDO> allNodes = listByCatalog(catalogId);
        if (CollectionUtils.isEmpty(allNodes)) {
            return new ArrayList<>();
        }
        
        // 2. 转换为VO
        List<ResourceCatalogItemTreeNodeVO> allVOs = allNodes.stream()
                .map(node -> BeanUtils.toBean(node, ResourceCatalogItemTreeNodeVO.class))
                .collect(Collectors.toList());
        
        // 3. 构建树形结构
        return buildTree(allVOs);
    }
    
    /**
     * 构建树形结构
     * 
     * @param allNodes 所有节点（已按path排序）
     * @return 树形结构（只返回根节点）
     */
    private List<ResourceCatalogItemTreeNodeVO> buildTree(List<ResourceCatalogItemTreeNodeVO> allNodes) {
        // 1. 创建path到节点的映射
        Map<String, ResourceCatalogItemTreeNodeVO> pathMap = new HashMap<>();
        for (ResourceCatalogItemTreeNodeVO node : allNodes) {
            // 跳过path为null或空的节点
            if (node.getPath() == null || node.getPath().length == 0) {
                continue;
            }
            String pathKey = String.join("/", node.getPath());
            pathMap.put(pathKey, node);
            node.setChildren(new ArrayList<>());
        }
        
        // 2. 构建父子关系
        List<ResourceCatalogItemTreeNodeVO> rootNodes = new ArrayList<>();
        for (ResourceCatalogItemTreeNodeVO node : allNodes) {
            // 跳过path为null或空的节点
            if (node.getPath() == null || node.getPath().length == 0) {
                continue;
            }
            
            if (node.getPath().length == 1) {
                // 根节点
                rootNodes.add(node);
            } else {
                // 非根节点，找到父节点并添加到children
                String[] parentPath = new String[node.getPath().length - 1];
                System.arraycopy(node.getPath(), 0, parentPath, 0, parentPath.length);
                String parentPathKey = String.join("/", parentPath);
                
                ResourceCatalogItemTreeNodeVO parent = pathMap.get(parentPathKey);
                if (parent != null) {
                    parent.getChildren().add(node);
                }
            }
        }
        
        // 3. 对所有节点的子节点按 sortOrder 排序
        sortChildrenBySortOrder(rootNodes);
        
        return rootNodes;
    }
    
    /**
     * 递归对所有节点的子节点按 sortOrder 排序
     */
    private void sortChildrenBySortOrder(List<ResourceCatalogItemTreeNodeVO> nodes) {
        if (nodes == null || nodes.isEmpty()) {
            return;
        }
        
        // 对当前层级按 sortOrder 排序
        nodes.sort((a, b) -> {
            Integer sortA = a.getSortOrder() != null ? a.getSortOrder() : 0;
            Integer sortB = b.getSortOrder() != null ? b.getSortOrder() : 0;
            return sortA.compareTo(sortB);
        });
        
        // 递归对每个节点的子节点排序
        for (ResourceCatalogItemTreeNodeVO node : nodes) {
            if (node.getChildren() != null && !node.getChildren().isEmpty()) {
                sortChildrenBySortOrder(node.getChildren());
            }
        }
    }

    private void checkCodeUnique(Long tenantId, Long catalogId, String code, Long excludeId) {
        LambdaQueryWrapper<ResourceCatalogItemDO> wrapper = new LambdaQueryWrapper<ResourceCatalogItemDO>()
                .eq(ResourceCatalogItemDO::getTenantId, tenantId)
                .eq(ResourceCatalogItemDO::getCategoryTreeId, catalogId)
                .eq(ResourceCatalogItemDO::getCode, code);
        if (excludeId != null) {
            wrapper.ne(ResourceCatalogItemDO::getId, excludeId);
        }
        ResourceCatalogItemDO exists = catalogItemMapper.selectOne(wrapper);
        if (exists != null) {
            throw exception0(BAD_REQUEST.getCode(), "条目编码已存在");
        }
    }

    /**
     * 检查根节点唯一性（一个工料机专业节点只能有一个根目录）
     */
    private void checkRootNodeUnique(Long tenantId, Long categoryTreeId) {
        // 查询是否已存在根节点（path 长度为 1 的节点）
        List<ResourceCatalogItemDO> allNodes = catalogItemMapper.selectList(
                new LambdaQueryWrapper<ResourceCatalogItemDO>()
                        .eq(ResourceCatalogItemDO::getTenantId, tenantId)
                        .eq(ResourceCatalogItemDO::getCategoryTreeId, categoryTreeId)
        );
        
        // 检查是否已存在根节点
        boolean hasRootNode = allNodes.stream()
                .anyMatch(node -> node.getPath() != null && node.getPath().length == 1);
        
        if (hasRootNode) {
            throw exception0(BAD_REQUEST.getCode(), "一个工料机专业节点只能有一个根目录");
        }
    }

    private String[] buildPath(List<String> parentPath, String code) {
        List<String> path = new ArrayList<>();
        if (!CollectionUtils.isEmpty(parentPath)) {
            path.addAll(parentPath);
        }
        path.add(code);
        return ArrayUtils.toArray(path, s -> s);
    }
    
    @Override
    public List<ResourceCategorySimpleRespVO> getAllowedCategories(Long catalogItemId) {
        // 1. 查询目录树节点
        ResourceCatalogItemDO catalogItem = catalogItemMapper.selectById(catalogItemId);
        if (catalogItem == null) {
            // 节点不存在时返回空列表，避免前端报错
            return new ArrayList<>();
        }
        
        // 2. 检查 categoryTreeId 是否存在
        if (catalogItem.getCategoryTreeId() == null) {
            return new ArrayList<>();
        }
        
        // 3. 查询该目录树节点所属的机类树节点允许的类别列表
        return categoryTreeService.getCategoriesByTreeNode(catalogItem.getCategoryTreeId());
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSortOrder(Long nodeId1, Long nodeId2) {
        Long tenantId = TenantContextHolder.getTenantId();
        
        // 1. 查询两个节点
        ResourceCatalogItemDO node1 = catalogItemMapper.selectOne(
                new LambdaQueryWrapper<ResourceCatalogItemDO>()
                        .eq(ResourceCatalogItemDO::getId, nodeId1)
                        .eq(ResourceCatalogItemDO::getTenantId, tenantId)
        );
        ResourceCatalogItemDO node2 = catalogItemMapper.selectOne(
                new LambdaQueryWrapper<ResourceCatalogItemDO>()
                        .eq(ResourceCatalogItemDO::getId, nodeId2)
                        .eq(ResourceCatalogItemDO::getTenantId, tenantId)
        );
        
        if (node1 == null || node2 == null) {
            throw exception0(BAD_REQUEST.getCode(), "目录树节点不存在");
        }
        
        // 2. 验证是否同级（path 长度必须相同，且父路径必须相同）
        if (!isSameLevel(node1.getPath(), node2.getPath())) {
            throw exception0(BAD_REQUEST.getCode(), "只能在同级节点之间调整排序");
        }
        
        // 3. 交换 sort_order
        Integer tempSortOrder = node1.getSortOrder();
        node1.setSortOrder(node2.getSortOrder());
        node2.setSortOrder(tempSortOrder);
        
        // 4. 更新数据库
        catalogItemMapper.updateById(node1);
        catalogItemMapper.updateById(node2);
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void dragNode(Long dragNodeId, Long targetNodeId, String position) {
        Long tenantId = TenantContextHolder.getTenantId();
        
        // 1. 查询拖动节点和目标节点（使用行锁）
        ResourceCatalogItemDO dragNode = catalogItemMapper.selectOne(
                new LambdaQueryWrapper<ResourceCatalogItemDO>()
                        .eq(ResourceCatalogItemDO::getId, dragNodeId)
                        .eq(ResourceCatalogItemDO::getTenantId, tenantId)
                        .last("FOR UPDATE")
        );
        
        ResourceCatalogItemDO targetNode = catalogItemMapper.selectOne(
                new LambdaQueryWrapper<ResourceCatalogItemDO>()
                        .eq(ResourceCatalogItemDO::getId, targetNodeId)
                        .eq(ResourceCatalogItemDO::getTenantId, tenantId)
                        .last("FOR UPDATE")
        );
        
        if (dragNode == null || targetNode == null) {
            throw exception0(BAD_REQUEST.getCode(), "节点不存在");
        }
        
        // 2. 验证是否同级（path 长度相同且父路径相同）
        if (!isSameLevel(dragNode.getPath(), targetNode.getPath())) {
            throw exception0(BAD_REQUEST.getCode(), "只能在同级节点之间拖动");
        }
        
        // 3. 查询同级节点列表
        List<ResourceCatalogItemDO> siblings = getSiblingNodes(dragNode.getCategoryTreeId(), dragNode.getPath(), tenantId);
        
        // 4. 移除拖动节点
        siblings.removeIf(node -> node.getId().equals(dragNodeId));
        
        // 5. 找到目标节点位置
        int targetIndex = -1;
        for (int i = 0; i < siblings.size(); i++) {
            if (siblings.get(i).getId().equals(targetNodeId)) {
                targetIndex = i;
                break;
            }
        }
        
        if (targetIndex == -1) {
            throw exception0(BAD_REQUEST.getCode(), "目标节点不存在");
        }
        
        // 6. 根据位置插入拖动节点
        if ("before".equals(position)) {
            siblings.add(targetIndex, dragNode);
        } else if ("after".equals(position)) {
            siblings.add(targetIndex + 1, dragNode);
        } else {
            throw exception0(BAD_REQUEST.getCode(), "无效的插入位置");
        }
        
        // 7. 重新分配 sortOrder
        for (int i = 0; i < siblings.size(); i++) {
            siblings.get(i).setSortOrder(i + 1);
        }
        catalogItemMapper.updateBatch(siblings);
    }
    
    /**
     * 判断两个节点是否同级（通过 path 数组判断）
     */
    private boolean isSameLevel(String[] path1, String[] path2) {
        if (path1 == null || path2 == null) {
            return false;
        }
        
        // 长度必须相同
        if (path1.length != path2.length) {
            return false;
        }
        
        // 如果是根节点（长度为1），直接返回 true
        if (path1.length == 1) {
            return true;
        }
        
        // 父路径必须相同（除了最后一个元素）
        for (int i = 0; i < path1.length - 1; i++) {
            if (!path1[i].equals(path2[i])) {
                return false;
            }
        }
        
        return true;
    }
    
    @Override
    public List<ResourceCatalogItemDO> listByPathLevel(Integer pathLength) {
        if (pathLength == null || pathLength < 1) {
            pathLength = 2;
        }
        //TenantContextHolder.getTenantId()
        return catalogItemMapper.selectByPathLevel(pathLength, 1L);
    }
    
    /**
     * 在指定位置插入新节点
     * @param newNode 新节点
     * @param referenceNodeId 参考节点ID
     * @param position 插入位置：above/below
     */
    private void insertNodeAtPosition(ResourceCatalogItemDO newNode, Long referenceNodeId, String position) {
        Long tenantId = TenantContextHolder.getTenantId();
        
        ResourceCatalogItemDO referenceNode = catalogItemMapper.selectById(referenceNodeId);
        if (referenceNode == null) {
            throw exception0(BAD_REQUEST.getCode(), "参考节点不存在");
        }
        
        // 验证是否同级（path 长度相同且父路径相同）
        if (!isSameLevel(newNode.getPath(), referenceNode.getPath())) {
            throw exception0(BAD_REQUEST.getCode(), "参考节点与新节点不在同一层级");
        }
        
        // 查询同级节点（按 sortOrder 排序）
        List<ResourceCatalogItemDO> siblings = getSiblingNodes(newNode.getCategoryTreeId(), newNode.getPath(), tenantId);
        
        // 先移除新节点（如果已存在于列表中），避免影响 referenceIndex 计算
        siblings.removeIf(node -> node.getId().equals(newNode.getId()));
        
        // 找到参考节点的位置
        int referenceIndex = -1;
        for (int i = 0; i < siblings.size(); i++) {
            if (siblings.get(i).getId().equals(referenceNodeId)) {
                referenceIndex = i;
                break;
            }
        }
        
        if (referenceIndex == -1) {
            // 参考节点不在同级节点中，回退到普通排序
            reorderSiblings(newNode.getCategoryTreeId(), newNode.getPath());
            return;
        }
        
        // 在指定位置插入新节点
        if ("above".equals(position)) {
            siblings.add(referenceIndex, newNode);
        } else if ("below".equals(position)) {
            siblings.add(referenceIndex + 1, newNode);
        } else {
            siblings.add(newNode);
        }
        
        // 重新分配 sortOrder
        for (int i = 0; i < siblings.size(); i++) {
            siblings.get(i).setSortOrder(i + 1);
        }
        catalogItemMapper.updateBatch(siblings);
    }
    
    /**
     * 重新排序同级节点
     * @param categoryTreeId 机类树ID
     * @param path 当前节点路径（用于确定层级）
     */
    private void reorderSiblings(Long categoryTreeId, String[] path) {
        Long tenantId = TenantContextHolder.getTenantId();
        
        List<ResourceCatalogItemDO> siblings = getSiblingNodes(categoryTreeId, path, tenantId);
        if (siblings.isEmpty()) {
            return;
        }
        
        // 重新分配 sortOrder
        for (int i = 0; i < siblings.size(); i++) {
            siblings.get(i).setSortOrder(i + 1);
        }
        catalogItemMapper.updateBatch(siblings);
    }
    
    /**
     * 获取同级节点列表
     * @param categoryTreeId 机类树ID
     * @param path 当前节点路径
     * @param tenantId 租户ID
     * @return 同级节点列表
     */
    private List<ResourceCatalogItemDO> getSiblingNodes(Long categoryTreeId, String[] path, Long tenantId) {
        // 构建父路径条件
        if (path == null || path.length == 0) {
            return new ArrayList<>();
        }
        
        // 获取父路径（去掉最后一个元素）
        String[] parentPath = null;
        if (path.length > 1) {
            parentPath = new String[path.length - 1];
            System.arraycopy(path, 0, parentPath, 0, parentPath.length);
        }
        
        LambdaQueryWrapper<ResourceCatalogItemDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ResourceCatalogItemDO::getTenantId, tenantId)
                .eq(ResourceCatalogItemDO::getCategoryTreeId, categoryTreeId);
        
        if (parentPath == null) {
            // 根节点：path 长度为 1
            queryWrapper.apply("array_length(path, 1) = 1");
        } else {
            // 非根节点：父路径相同
            // 构建数组字符串（parentPath 来自数据库 path 字段，是 ID 值，安全）
            String arrayStr = "ARRAY['" + String.join("','", parentPath) + "']::varchar[]";
            queryWrapper.apply("path[1:array_length(path,1)-1]::varchar[] = " + arrayStr);
        }
        
        queryWrapper.orderByAsc(ResourceCatalogItemDO::getSortOrder);
        
        return catalogItemMapper.selectList(queryWrapper);
    }
}
