package com.lingyue.graph.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.lingyue.common.exception.ServiceException;
import com.lingyue.graph.dto.BatchCreateNodesRequest;
import com.lingyue.graph.dto.BatchCreateRelationsRequest;
import com.lingyue.graph.dto.CreateNodeRequest;
import com.lingyue.graph.dto.CreateRelationRequest;
import com.lingyue.graph.entity.GraphNode;
import com.lingyue.graph.entity.GraphRelation;
import com.lingyue.graph.repository.GraphNodeRepository;
import com.lingyue.graph.repository.GraphRelationRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 图节点服务
 * 提供图节点和关系的 CRUD 及批量操作
 *
 * @author lingyue
 * @since 2026-01-19
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GraphNodeService {

    private final GraphNodeRepository graphNodeRepository;
    private final GraphRelationRepository graphRelationRepository;

    // ==================== 节点操作 ====================

    /**
     * 创建单个节点
     */
    public GraphNode createNode(CreateNodeRequest request) {
        GraphNode node = new GraphNode();
        node.setId(UUID.randomUUID().toString().replace("-", ""));
        node.setDocumentId(request.getDocumentId());
        node.setUserId(request.getUserId());  // 可为 null
        node.setName(request.getName());
        node.setType(request.getType());
        node.setValue(request.getValue());
        node.setPosition(request.getPosition());
        node.setParentId(request.getParentId());
        node.setLevel(request.getLevel() != null ? request.getLevel() : 0);
        node.setMetadata(request.getMetadata());
        node.setCreateTime(new Date());
        node.setUpdateTime(new Date());

        graphNodeRepository.insert(node);
        log.debug("创建节点: id={}, name={}, type={}", node.getId(), node.getName(), node.getType());

        return node;
    }

    /**
     * 批量创建节点
     *
     * @return 创建的节点列表
     */
    @Transactional
    public List<GraphNode> batchCreateNodes(BatchCreateNodesRequest request) {
        if (request.getNodes() == null || request.getNodes().isEmpty()) {
            return Collections.emptyList();
        }

        String documentId = request.getDocumentId();
        String userId = request.getUserId();

        // 如果需要替换已有节点，先删除
        if (Boolean.TRUE.equals(request.getReplaceExisting()) && documentId != null) {
            deleteNodesByDocumentId(documentId);
        }

        List<GraphNode> createdNodes = new ArrayList<>();
        for (CreateNodeRequest nodeRequest : request.getNodes()) {
            // 设置文档ID和用户ID
            if (nodeRequest.getDocumentId() == null) {
                nodeRequest.setDocumentId(documentId);
            }
            if (nodeRequest.getUserId() == null) {
                nodeRequest.setUserId(userId);
            }

            GraphNode node = createNode(nodeRequest);
            createdNodes.add(node);
        }

        log.info("批量创建节点完成: documentId={}, count={}", documentId, createdNodes.size());
        return createdNodes;
    }

    /**
     * 根据ID获取节点
     */
    public GraphNode getNodeById(String nodeId) {
        return graphNodeRepository.selectById(nodeId);
    }

    /**
     * 根据文档ID获取所有节点
     */
    public List<GraphNode> getNodesByDocumentId(String documentId) {
        return graphNodeRepository.findByDocumentId(documentId);
    }

    /**
     * 根据文档ID和类型获取节点
     */
    public List<GraphNode> getNodesByDocumentIdAndType(String documentId, String type) {
        return graphNodeRepository.findByDocumentIdAndType(documentId, type);
    }

    /**
     * 根据用户ID获取节点
     */
    public List<GraphNode> getNodesByUserId(String userId) {
        return graphNodeRepository.findByUserId(userId);
    }

    /**
     * 更新节点
     */
    public GraphNode updateNode(String nodeId, CreateNodeRequest request) {
        GraphNode node = graphNodeRepository.selectById(nodeId);
        if (node == null) {
            throw new ServiceException("节点不存在: " + nodeId);
        }

        if (request.getName() != null) {
            node.setName(request.getName());
        }
        if (request.getType() != null) {
            node.setType(request.getType());
        }
        if (request.getValue() != null) {
            node.setValue(request.getValue());
        }
        if (request.getPosition() != null) {
            node.setPosition(request.getPosition());
        }
        if (request.getParentId() != null) {
            node.setParentId(request.getParentId());
        }
        if (request.getLevel() != null) {
            node.setLevel(request.getLevel());
        }
        if (request.getMetadata() != null) {
            node.setMetadata(request.getMetadata());
        }
        node.setUpdateTime(new Date());

        graphNodeRepository.updateById(node);
        log.debug("更新节点: id={}", nodeId);

        return node;
    }

    /**
     * 删除节点（同时删除相关关系）
     */
    @Transactional
    public void deleteNode(String nodeId) {
        // 先删除相关关系
        deleteRelationsByNodeId(nodeId);
        // 再删除节点
        graphNodeRepository.deleteById(nodeId);
        log.debug("删除节点: id={}", nodeId);
    }

    /**
     * 根据文档ID删除所有节点（同时删除相关关系）
     */
    @Transactional
    public int deleteNodesByDocumentId(String documentId) {
        // 获取所有节点ID
        List<GraphNode> nodes = graphNodeRepository.findByDocumentId(documentId);
        if (nodes.isEmpty()) {
            return 0;
        }

        // 删除所有相关关系
        for (GraphNode node : nodes) {
            deleteRelationsByNodeId(node.getId());
        }

        // 删除节点
        LambdaQueryWrapper<GraphNode> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GraphNode::getDocumentId, documentId);
        int count = graphNodeRepository.delete(wrapper);

        log.info("删除文档节点: documentId={}, count={}", documentId, count);
        return count;
    }

    // ==================== 关系操作 ====================

    /**
     * 创建单个关系
     */
    public GraphRelation createRelation(CreateRelationRequest request) {
        // 验证节点存在
        if (graphNodeRepository.selectById(request.getFromNodeId()) == null) {
            throw new ServiceException("源节点不存在: " + request.getFromNodeId());
        }
        if (graphNodeRepository.selectById(request.getToNodeId()) == null) {
            throw new ServiceException("目标节点不存在: " + request.getToNodeId());
        }

        GraphRelation relation = new GraphRelation();
        relation.setId(UUID.randomUUID().toString().replace("-", ""));
        relation.setFromNodeId(request.getFromNodeId());
        relation.setToNodeId(request.getToNodeId());
        relation.setRelationType(request.getRelationType());
        relation.setActionType(request.getActionType());
        relation.setActionConfig(request.getActionConfig());
        relation.setOrderIndex(request.getOrderIndex() != null ? request.getOrderIndex() : 0);
        relation.setConditionExpr(request.getConditionExpr());
        relation.setMetadata(request.getMetadata());
        relation.setCreateTime(new Date());
        relation.setUpdateTime(new Date());

        graphRelationRepository.insert(relation);
        log.debug("创建关系: id={}, from={}, to={}, type={}",
                relation.getId(), relation.getFromNodeId(), relation.getToNodeId(), relation.getRelationType());

        return relation;
    }

    /**
     * 批量创建关系
     */
    @Transactional
    public List<GraphRelation> batchCreateRelations(BatchCreateRelationsRequest request) {
        if (request.getRelations() == null || request.getRelations().isEmpty()) {
            return Collections.emptyList();
        }

        List<GraphRelation> createdRelations = new ArrayList<>();
        boolean skipInvalid = Boolean.TRUE.equals(request.getSkipInvalidNodes());

        for (CreateRelationRequest relationRequest : request.getRelations()) {
            try {
                GraphRelation relation = createRelation(relationRequest);
                createdRelations.add(relation);
            } catch (ServiceException e) {
                if (skipInvalid) {
                    log.warn("跳过无效关系: from={}, to={}, error={}",
                            relationRequest.getFromNodeId(), relationRequest.getToNodeId(), e.getMessage());
                } else {
                    throw e;
                }
            }
        }

        log.info("批量创建关系完成: count={}", createdRelations.size());
        return createdRelations;
    }

    /**
     * 根据ID获取关系
     */
    public GraphRelation getRelationById(String relationId) {
        return graphRelationRepository.selectById(relationId);
    }

    /**
     * 根据源节点ID获取关系
     */
    public List<GraphRelation> getRelationsByFromNodeId(String fromNodeId) {
        return graphRelationRepository.findByFromNodeId(fromNodeId);
    }

    /**
     * 根据目标节点ID获取关系
     */
    public List<GraphRelation> getRelationsByToNodeId(String toNodeId) {
        return graphRelationRepository.findByToNodeId(toNodeId);
    }

    /**
     * 根据节点ID获取所有相关关系
     */
    public List<GraphRelation> getRelationsByNodeId(String nodeId) {
        return graphRelationRepository.findByNodeId(nodeId);
    }

    /**
     * 删除关系
     */
    public void deleteRelation(String relationId) {
        graphRelationRepository.deleteById(relationId);
        log.debug("删除关系: id={}", relationId);
    }

    /**
     * 删除节点相关的所有关系
     */
    public int deleteRelationsByNodeId(String nodeId) {
        LambdaQueryWrapper<GraphRelation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GraphRelation::getFromNodeId, nodeId)
                .or()
                .eq(GraphRelation::getToNodeId, nodeId);
        int count = graphRelationRepository.delete(wrapper);
        log.debug("删除节点相关关系: nodeId={}, count={}", nodeId, count);
        return count;
    }

    // ==================== 统计操作 ====================

    /**
     * 获取文档的节点统计
     */
    public Map<String, Object> getNodeStatsByDocumentId(String documentId) {
        List<GraphNode> nodes = graphNodeRepository.findByDocumentId(documentId);

        Map<String, Long> typeCount = new HashMap<>();
        for (GraphNode node : nodes) {
            String type = node.getType() != null ? node.getType() : "other";
            typeCount.put(type, typeCount.getOrDefault(type, 0L) + 1);
        }

        Map<String, Object> stats = new HashMap<>();
        stats.put("totalNodes", nodes.size());
        stats.put("typeDistribution", typeCount);

        return stats;
    }

    /**
     * 获取文档的关系统计
     */
    public Map<String, Object> getRelationStatsByDocumentId(String documentId) {
        List<GraphNode> nodes = graphNodeRepository.findByDocumentId(documentId);
        Set<String> nodeIds = new HashSet<>();
        for (GraphNode node : nodes) {
            nodeIds.add(node.getId());
        }

        int relationCount = 0;
        Map<String, Long> typeCount = new HashMap<>();

        for (String nodeId : nodeIds) {
            List<GraphRelation> relations = graphRelationRepository.findByFromNodeId(nodeId);
            for (GraphRelation relation : relations) {
                if (nodeIds.contains(relation.getToNodeId())) {
                    relationCount++;
                    String type = relation.getRelationType() != null ? relation.getRelationType() : "OTHER";
                    typeCount.put(type, typeCount.getOrDefault(type, 0L) + 1);
                }
            }
        }

        Map<String, Object> stats = new HashMap<>();
        stats.put("totalRelations", relationCount);
        stats.put("typeDistribution", typeCount);

        return stats;
    }
}
