package com.ruoyi.system.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.stereotype.Service;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.neo4j.GraphNode;
import com.ruoyi.system.repository.neo4j.GraphNodeRepository;
import com.ruoyi.system.service.IFloodKnowledgeGraphService;

/**
 * 洪水知识图谱Service业务层处理
 *
 * @author jackeyhuang
 * @version 1.0.0
 * @date 2025-01-27
 */
@Service
public class FloodKnowledgeGraphServiceImpl implements IFloodKnowledgeGraphService
{
    private static final Logger log = LoggerFactory.getLogger(FloodKnowledgeGraphServiceImpl.class);

    @Autowired
    private GraphNodeRepository graphNodeRepository;

    @Autowired
    private Neo4jClient neo4jClient;

    /**
     * 获取知识图谱数据
     *
     * @return 图谱数据
     */
    @Override
    public Map<String, Object> getGraphData()
    {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> nodes = new ArrayList<>();
        List<Map<String, Object>> edges = new ArrayList<>();

        try
        {
            // 查询所有节点（限制数量避免数据过大）
            List<GraphNode> nodeList = graphNodeRepository.findAllWithRelationships();
            
            // 如果节点为空，返回示例数据
            if (nodeList == null || nodeList.isEmpty())
            {
                log.warn("Neo4j数据库中没有找到节点数据，返回示例数据");
                return getExampleGraphData();
            }

            // 创建节点ID映射（Neo4j内部ID -> 字符串ID）
            Map<Long, String> nodeIdMap = new HashMap<>();
            
            // 转换节点数据
            int index = 0;
            for (GraphNode node : nodeList)
            {
                Map<String, Object> nodeMap = new HashMap<>();
                // 使用节点ID作为唯一标识
                String nodeId = node.getId() != null ? node.getId().toString() : "node_" + index;
                nodeMap.put("id", nodeId);
                nodeMap.put("label", node.getLabel());
                nodeMap.put("type", node.getType());
                nodeMap.put("description", node.getDescription());
                if (node.getProperties() != null)
                {
                    nodeMap.putAll(node.getProperties());
                }
                nodes.add(nodeMap);
                
                // 保存ID映射
                if (node.getId() != null)
                {
                    nodeIdMap.put(node.getId(), nodeId);
                }
                index++;
            }

            // 查询所有关系，使用toString确保ID格式一致
            String cypher = "MATCH (n:KnowledgeNode)-[r:RELATED_TO]->(m:KnowledgeNode) RETURN toString(id(n)) as source, toString(id(m)) as target, r.relation as relation, r.weight as weight LIMIT 500";
            List<Map<String, Object>> relationships = neo4jClient
                .query(cypher)
                .fetch()
                .all()
                .stream()
                .map(record -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("source", record.get("source"));
                    map.put("target", record.get("target"));
                    map.put("relation", record.get("relation"));
                    map.put("weight", record.get("weight"));
                    return map;
                })
                .collect(java.util.stream.Collectors.toList());

            for (Map<String, Object> rel : relationships)
            {
                Map<String, Object> edgeMap = new HashMap<>();
                Object sourceObj = rel.get("source");
                Object targetObj = rel.get("target");
                
                // 处理source和target，可能是String或Number
                String sourceId = sourceObj != null ? sourceObj.toString() : "";
                String targetId = targetObj != null ? targetObj.toString() : "";
                
                edgeMap.put("source", sourceId);
                edgeMap.put("target", targetId);
                edgeMap.put("relation", rel.get("relation"));
                if (rel.get("weight") != null)
                {
                    edgeMap.put("weight", rel.get("weight"));
                }
                edges.add(edgeMap);
            }

            result.put("nodes", nodes);
            result.put("edges", edges);
        }
        catch (Exception e)
        {
            log.error("获取知识图谱数据失败", e);
            // 返回示例数据
            return getExampleGraphData();
        }

        return result;
    }

    /**
     * 根据节点ID查询节点详情
     *
     * @param nodeId 节点ID
     * @return 节点信息
     */
    @Override
    public GraphNode getNodeById(Long nodeId)
    {
        try
        {
            Optional<GraphNode> node = graphNodeRepository.findById(nodeId);
            return node.orElse(null);
        }
        catch (Exception e)
        {
            log.error("查询节点详情失败，nodeId: " + nodeId, e);
            return null;
        }
    }

    /**
     * 根据标签查询节点
     *
     * @param label 节点标签
     * @return 节点列表
     */
    @Override
    public List<GraphNode> getNodesByLabel(String label)
    {
        try
        {
            if (StringUtils.isEmpty(label))
            {
                return new ArrayList<>();
            }
            return graphNodeRepository.findByLabelContaining(label);
        }
        catch (Exception e)
        {
            log.error("根据标签查询节点失败，label: " + label, e);
            return new ArrayList<>();
        }
    }

    /**
     * 根据类型查询节点
     *
     * @param type 节点类型
     * @return 节点列表
     */
    @Override
    public List<GraphNode> getNodesByType(String type)
    {
        try
        {
            if (StringUtils.isEmpty(type))
            {
                return new ArrayList<>();
            }
            return graphNodeRepository.findByType(type);
        }
        catch (Exception e)
        {
            log.error("根据类型查询节点失败，type: " + type, e);
            return new ArrayList<>();
        }
    }

    /**
     * 查询两个节点之间的最短路径
     *
     * @param startNodeId 起始节点ID
     * @param endNodeId 结束节点ID
     * @param maxDepth 最大深度
     * @return 路径信息
     */
    @Override
    public Map<String, Object> findShortestPath(Long startNodeId, Long endNodeId, int maxDepth)
    {
        Map<String, Object> result = new HashMap<>();
        try
        {
            List<Object> pathData = graphNodeRepository.findShortestPath(startNodeId, endNodeId, maxDepth);
            result.put("path", pathData);
            result.put("success", true);
        }
        catch (Exception e)
        {
            log.error("查询最短路径失败", e);
            result.put("success", false);
            result.put("message", e.getMessage());
        }
        return result;
    }

    /**
     * 获取示例图谱数据（当Neo4j中没有数据时返回）
     *
     * @return 示例数据
     */
    private Map<String, Object> getExampleGraphData()
    {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> nodes = new ArrayList<>();
        List<Map<String, Object>> edges = new ArrayList<>();

        // 示例节点
        Map<String, Object> node1 = new HashMap<>();
        node1.put("id", "1");
        node1.put("label", "洪水");
        node1.put("type", "concept");
        node1.put("description", "洪水是一种自然灾害");
        nodes.add(node1);

        Map<String, Object> node2 = new HashMap<>();
        node2.put("id", "2");
        node2.put("label", "长江");
        node2.put("type", "location");
        node2.put("description", "中国第一大河");
        nodes.add(node2);

        Map<String, Object> node3 = new HashMap<>();
        node3.put("id", "3");
        node3.put("label", "1998年特大洪水");
        node3.put("type", "event");
        node3.put("description", "1998年长江全流域特大洪水");
        nodes.add(node3);

        // 示例关系
        Map<String, Object> edge1 = new HashMap<>();
        edge1.put("source", "1");
        edge1.put("target", "2");
        edge1.put("relation", "发生在");
        edges.add(edge1);

        Map<String, Object> edge2 = new HashMap<>();
        edge2.put("source", "3");
        edge2.put("target", "2");
        edge2.put("relation", "发生在");
        edges.add(edge2);

        Map<String, Object> edge3 = new HashMap<>();
        edge3.put("source", "3");
        edge3.put("target", "1");
        edge3.put("relation", "属于");
        edges.add(edge3);

        result.put("nodes", nodes);
        result.put("edges", edges);
        return result;
    }

    /**
     * 获取所有知识图谱列表（按类型分组）
     *
     * @return 图谱列表
     */
    @Override
    public List<Map<String, Object>> getAllGraphs()
    {
        List<Map<String, Object>> graphList = new ArrayList<>();
        
        try
        {
            // 查询所有不同的节点类型
            String cypher = "MATCH (n:Category) RETURN DISTINCT n.type as type, count(n) as nodeCount ORDER BY nodeCount DESC";
            List<Map<String, Object>> typeStats = neo4jClient
                .query(cypher)
                .fetch()
                .all()
                .stream()
                .map(record -> {
                    Map<String, Object> map = new HashMap<>();
                    String type = record.get("type") != null ? record.get("type").toString() : "other";
                    map.put("key", type);
                    map.put("name", getTypeDisplayName(type));
                    map.put("nodeCount", record.get("nodeCount"));
                    map.put("type", type);
                    return map;
                })
                .collect(java.util.stream.Collectors.toList());

            // 添加"全部"选项
            Map<String, Object> allGraph = new HashMap<>();
            allGraph.put("key", "all");
            allGraph.put("name", "全部图谱");
            allGraph.put("nodeCount", graphNodeRepository.count());
            allGraph.put("type", "all");
            graphList.add(allGraph);

            // 添加按类型分组的图谱
            graphList.addAll(typeStats);

            // 如果类型分组为空，至少返回"全部"选项
            if (graphList.size() == 1)
            {
                log.warn("Neo4j数据库中没有找到节点数据");
            }
        }
        catch (Exception e)
        {
            log.error("获取知识图谱列表失败", e);
            // 返回默认选项
            Map<String, Object> defaultGraph = new HashMap<>();
            defaultGraph.put("key", "all");
            defaultGraph.put("name", "全部图谱");
            defaultGraph.put("nodeCount", 0);
            defaultGraph.put("type", "all");
            graphList.add(defaultGraph);
        }

        return graphList;
    }

    /**
     * 根据图谱标识获取特定图谱数据
     *
     * @param graphKey 图谱标识（如类型：concept、location、event，或"all"表示全部）
     * @return 图谱数据
     */
    @Override
    public Map<String, Object> getGraphDataByKey(String graphKey)
    {
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> nodes = new ArrayList<>();
        List<Map<String, Object>> edges = new ArrayList<>();

        try
        {
            List<GraphNode> nodeList;
            
            // 如果graphKey为"all"或空，返回所有节点
            if (StringUtils.isEmpty(graphKey) || "all".equalsIgnoreCase(graphKey))
            {
                nodeList = graphNodeRepository.findAllWithRelationships();
            }
            else
            {
                // 根据类型查询节点
                nodeList = graphNodeRepository.findByType(graphKey);
            }

            // 如果节点为空，返回示例数据
            if (nodeList == null || nodeList.isEmpty())
            {
                log.warn("未找到指定类型的节点数据，graphKey: {}", graphKey);
                return getExampleGraphData();
            }

            // 创建节点ID映射
            Map<Long, String> nodeIdMap = new HashMap<>();
            
            // 转换节点数据
            int index = 0;
            for (GraphNode node : nodeList)
            {
                Map<String, Object> nodeMap = new HashMap<>();
                String nodeId = node.getId() != null ? node.getId().toString() : "node_" + index;
                nodeMap.put("id", nodeId);
                nodeMap.put("label", node.getLabel());
                nodeMap.put("type", node.getType());
                nodeMap.put("description", node.getDescription());
                if (node.getProperties() != null)
                {
                    nodeMap.putAll(node.getProperties());
                }
                nodes.add(nodeMap);
                
                if (node.getId() != null)
                {
                    nodeIdMap.put(node.getId(), nodeId);
                }
                index++;
            }

            // 查询这些节点之间的关系
            // 构建节点ID列表用于查询
            List<Long> nodeIds = nodeList.stream()
                .filter(n -> n.getId() != null)
                .map(GraphNode::getId)
                .collect(java.util.stream.Collectors.toList());

            if (!nodeIds.isEmpty())
            {
                // 查询这些节点之间的关系
                // 构建节点ID字符串用于Cypher查询
                String nodeIdsStr = nodeIds.stream()
                    .map(String::valueOf)
                    .collect(java.util.stream.Collectors.joining(","));
                
                String cypher = "MATCH (n:KnowledgeNode)-[r:RELATED_TO]->(m:KnowledgeNode) " +
                    "WHERE id(n) IN [" + nodeIdsStr + "] AND id(m) IN [" + nodeIdsStr + "] " +
                    "RETURN toString(id(n)) as source, toString(id(m)) as target, r.relation as relation, r.weight as weight " +
                    "LIMIT 500";
                
                List<Map<String, Object>> relationships = neo4jClient
                    .query(cypher)
                    .fetch()
                    .all()
                    .stream()
                    .map(record -> {
                        Map<String, Object> map = new HashMap<>();
                        map.put("source", record.get("source"));
                        map.put("target", record.get("target"));
                        map.put("relation", record.get("relation"));
                        map.put("weight", record.get("weight"));
                        return map;
                    })
                    .collect(java.util.stream.Collectors.toList());

                for (Map<String, Object> rel : relationships)
                {
                    Map<String, Object> edgeMap = new HashMap<>();
                    Object sourceObj = rel.get("source");
                    Object targetObj = rel.get("target");
                    
                    String sourceId = sourceObj != null ? sourceObj.toString() : "";
                    String targetId = targetObj != null ? targetObj.toString() : "";
                    
                    edgeMap.put("source", sourceId);
                    edgeMap.put("target", targetId);
                    edgeMap.put("relation", rel.get("relation"));
                    if (rel.get("weight") != null)
                    {
                        edgeMap.put("weight", rel.get("weight"));
                    }
                    edges.add(edgeMap);
                }
            }

            result.put("nodes", nodes);
            result.put("edges", edges);
        }
        catch (Exception e)
        {
            log.error("获取指定知识图谱数据失败，graphKey: {}", graphKey, e);
            // 返回示例数据
            return getExampleGraphData();
        }

        return result;
    }

    /**
     * 获取类型显示名称
     */
    private String getTypeDisplayName(String type)
    {
        if (StringUtils.isEmpty(type))
        {
            return "其他";
        }
        
        Map<String, String> typeNameMap = new HashMap<>();
        typeNameMap.put("concept", "概念图谱");
        typeNameMap.put("location", "地点图谱");
        typeNameMap.put("event", "事件图谱");
        typeNameMap.put("other", "其他图谱");
        
        return typeNameMap.getOrDefault(type.toLowerCase(), type + "图谱");
    }
}
