//! Property graph storage using petgraph.

use std::collections::{HashMap, HashSet};

use indexmap::IndexMap;
use petgraph::stable_graph::{EdgeIndex, NodeIndex, StableDiGraph};
use petgraph::visit::EdgeRef;
use petgraph::Direction;

use super::backend::GraphBackend;
use super::types::{GraphEdge, GraphNode, Path, PropertyValue};
use crate::error::{ExecutionError, ExecutionResult};

/// A property graph backed by petgraph's StableDiGraph.
#[derive(Debug)]
pub struct PropertyGraph {
    /// The underlying graph structure.
    pub(crate) graph: StableDiGraph<GraphNode, GraphEdge>,
    /// Index from node ID to graph node index.
    node_id_index: HashMap<u64, NodeIndex>,
    /// Index from edge ID to graph edge index.
    edge_id_index: HashMap<u64, EdgeIndex>,
    /// Index from label to set of node indices.
    label_index: HashMap<String, HashSet<NodeIndex>>,
    /// Index from relationship type to set of edge indices.
    rel_type_index: HashMap<String, HashSet<EdgeIndex>>,
    /// Label-property secondary index: (label, property) → set of node indices.
    /// Populated only for (label, property) pairs that have had `create_index` called.
    prop_index: HashMap<(String, String), HashMap<String, HashSet<NodeIndex>>>,
    /// Active UNIQUE constraints: set of (label, property) pairs.
    unique_constraints: HashSet<(String, String)>,
    /// Next available node ID.
    next_node_id: u64,
    /// Next available edge ID.
    next_edge_id: u64,
}

impl Default for PropertyGraph {
    fn default() -> Self {
        Self::new()
    }
}

impl PropertyGraph {
    /// Create a new empty property graph.
    pub fn new() -> Self {
        Self {
            graph: StableDiGraph::new(),
            node_id_index: HashMap::new(),
            edge_id_index: HashMap::new(),
            label_index: HashMap::new(),
            rel_type_index: HashMap::new(),
            prop_index: HashMap::new(),
            unique_constraints: HashSet::new(),
            next_node_id: 1,
            next_edge_id: 1,
        }
    }

    // ── Schema API ────────────────────────────────────────────────────────────

    /// Register a label-property index.  The index is built immediately from
    /// the current node set and kept up to date on future mutations.
    pub fn create_index_schema(&mut self, label: &str, property: &str) {
        let key = (label.to_string(), property.to_string());
        if self.prop_index.contains_key(&key) {
            return; // already indexed
        }
        let mut bucket: HashMap<String, HashSet<NodeIndex>> = HashMap::new();
        if let Some(node_set) = self.label_index.get(label) {
            for &idx in node_set {
                let node = &self.graph[idx];
                if let Some(pv) = node.properties.get(property) {
                    let s = format!("{pv:?}");
                    bucket.entry(s).or_default().insert(idx);
                }
            }
        }
        self.prop_index.insert(key, bucket);
    }

    /// Drop a label-property index.
    pub fn drop_index_schema(&mut self, label: &str, property: &str) {
        self.prop_index.remove(&(label.to_string(), property.to_string()));
    }

    /// Register a UNIQUE constraint on (label, property).
    /// Also ensures an index exists for efficient duplicate checks.
    pub fn create_unique_constraint_schema(&mut self, label: &str, property: &str) {
        self.create_index_schema(label, property);
        self.unique_constraints.insert((label.to_string(), property.to_string()));
    }

    /// Drop a UNIQUE constraint.
    pub fn drop_unique_constraint_schema(&mut self, label: &str, property: &str) {
        self.unique_constraints.remove(&(label.to_string(), property.to_string()));
    }

    /// Check whether creating a node with the given labels and properties would
    /// violate any active UNIQUE constraint.  Returns `Err(ConstraintViolation)`
    /// if so.
    pub fn check_unique_constraints(
        &self,
        labels: &[String],
        properties: &IndexMap<String, PropertyValue>,
    ) -> ExecutionResult<()> {
        for label in labels {
            for (prop, value) in properties {
                if self.unique_constraints.contains(&(label.clone(), prop.clone())) {
                    let key_str = format!("{value:?}");
                    if let Some(bucket) = self.prop_index.get(&(label.clone(), prop.clone())) {
                        if bucket.contains_key(&key_str) {
                            return Err(ExecutionError::ConstraintViolation(format!(
                                "Unique constraint on (:{label} {{{prop}}}) violated: value {key_str} already exists"
                            )));
                        }
                    }
                }
            }
        }
        Ok(())
    }

    /// Update the prop_index for a newly created/restored node.
    fn update_prop_index_for_node(&mut self, node_idx: NodeIndex) {
        let node = &self.graph[node_idx];
        let labels: Vec<String> = node.labels.iter().cloned().collect();
        let properties: Vec<(String, String)> = node
            .properties
            .iter()
            .map(|(k, v)| (k.clone(), format!("{v:?}")))
            .collect();
        for label in &labels {
            for (prop, val_str) in &properties {
                let key = (label.clone(), prop.clone());
                if let Some(bucket) = self.prop_index.get_mut(&key) {
                    bucket.entry(val_str.clone()).or_default().insert(node_idx);
                }
            }
        }
    }

    /// Remove a node's entries from the prop_index.
    fn remove_from_prop_index(&mut self, node_idx: NodeIndex) {
        let node = &self.graph[node_idx];
        let labels: Vec<String> = node.labels.iter().cloned().collect();
        let properties: Vec<(String, String)> = node
            .properties
            .iter()
            .map(|(k, v)| (k.clone(), format!("{v:?}")))
            .collect();
        for label in &labels {
            for (prop, val_str) in &properties {
                let key = (label.clone(), prop.clone());
                if let Some(bucket) = self.prop_index.get_mut(&key) {
                    if let Some(set) = bucket.get_mut(val_str.as_str()) {
                        set.remove(&node_idx);
                    }
                }
            }
        }
    }

    /// Fast lookup: nodes with given label and property equal to value.
    pub fn nodes_with_label_property_fast(
        &self,
        label: &str,
        property: &str,
        value: &PropertyValue,
    ) -> Vec<&GraphNode> {
        let key = (label.to_string(), property.to_string());
        if let Some(bucket) = self.prop_index.get(&key) {
            let val_str = format!("{value:?}");
            bucket
                .get(&val_str)
                .map(|set| set.iter().map(|&idx| &self.graph[idx]).collect())
                .unwrap_or_default()
        } else {
            // Fall back to label scan + filter
            self.nodes_with_label(label)
                .into_iter()
                .filter(|n| n.properties.get(property) == Some(value))
                .collect()
        }
    }

    /// Get the number of nodes in the graph.
    pub fn node_count(&self) -> usize {
        self.graph.node_count()
    }

    /// Get the number of edges in the graph.
    pub fn edge_count(&self) -> usize {
        self.graph.edge_count()
    }

    /// Create a new node with the given labels and properties.
    pub fn create_node(
        &mut self,
        labels: impl IntoIterator<Item = impl Into<String>>,
        properties: IndexMap<String, PropertyValue>,
    ) -> &GraphNode {
        let id = self.next_node_id;
        self.next_node_id += 1;

        let mut node = GraphNode::new(id);
        node.properties = properties;

        for label in labels {
            let label = label.into();
            node.labels.insert(label.clone());
        }

        let idx = self.graph.add_node(node);
        self.node_id_index.insert(id, idx);

        // Update label index
        let node = &self.graph[idx];
        for label in &node.labels {
            self.label_index
                .entry(label.clone())
                .or_default()
                .insert(idx);
        }

        // Update property index (for any active label-property indexes)
        self.update_prop_index_for_node(idx);

        &self.graph[idx]
    }

    /// Add an existing node with a pre-assigned ID to the graph.
    ///
    /// This is used by partitioned backends to add nodes with partition-aware IDs.
    pub fn add_existing_node(&mut self, node: GraphNode) -> &GraphNode {
        let id = node.id;
        let idx = self.graph.add_node(node);
        self.node_id_index.insert(id, idx);

        // Update label index
        let node = &self.graph[idx];
        for label in &node.labels {
            self.label_index
                .entry(label.clone())
                .or_default()
                .insert(idx);
        }

        // Update property index
        self.update_prop_index_for_node(idx);

        // Update next_node_id if necessary (for backward compatibility)
        if id >= self.next_node_id {
            self.next_node_id = id + 1;
        }

        &self.graph[idx]
    }

    /// Create a new relationship between two nodes.
    pub fn create_relationship(
        &mut self,
        start_id: u64,
        end_id: u64,
        rel_type: impl Into<String>,
        properties: IndexMap<String, PropertyValue>,
    ) -> ExecutionResult<&GraphEdge> {
        let start_idx = self
            .node_id_index
            .get(&start_id)
            .copied()
            .ok_or(ExecutionError::NodeNotFound(start_id))?;
        let end_idx = self
            .node_id_index
            .get(&end_id)
            .copied()
            .ok_or(ExecutionError::NodeNotFound(end_id))?;

        let id = self.next_edge_id;
        self.next_edge_id += 1;

        let rel_type = rel_type.into();
        let mut edge = GraphEdge::new(id, rel_type.clone());
        edge.properties = properties;

        let edge_idx = self.graph.add_edge(start_idx, end_idx, edge);
        self.edge_id_index.insert(id, edge_idx);

        // Update rel type index
        self.rel_type_index
            .entry(rel_type)
            .or_default()
            .insert(edge_idx);

        Ok(&self.graph[edge_idx])
    }

    /// Create a new relationship with a pre-assigned edge ID.
    ///
    /// This is used by partitioned backends to create edges with partition-aware IDs.
    pub fn create_relationship_with_id(
        &mut self,
        edge_id: u64,
        start_id: u64,
        end_id: u64,
        rel_type: impl Into<String>,
        properties: IndexMap<String, PropertyValue>,
    ) -> ExecutionResult<u64> {
        let start_idx = self
            .node_id_index
            .get(&start_id)
            .copied()
            .ok_or(ExecutionError::NodeNotFound(start_id))?;
        let end_idx = self
            .node_id_index
            .get(&end_id)
            .copied()
            .ok_or(ExecutionError::NodeNotFound(end_id))?;

        let rel_type = rel_type.into();
        let mut edge = GraphEdge::new(edge_id, rel_type.clone());
        edge.properties = properties;

        let edge_idx = self.graph.add_edge(start_idx, end_idx, edge);
        self.edge_id_index.insert(edge_id, edge_idx);

        // Update rel type index
        self.rel_type_index
            .entry(rel_type)
            .or_default()
            .insert(edge_idx);

        // Update next_edge_id if necessary (for backward compatibility)
        if edge_id >= self.next_edge_id {
            self.next_edge_id = edge_id + 1;
        }

        Ok(edge_id)
    }

    /// Get a node by its ID.
    pub fn get_node(&self, id: u64) -> Option<&GraphNode> {
        self.node_id_index
            .get(&id)
            .and_then(|idx| self.graph.node_weight(*idx))
    }

    /// Get a mutable node by its ID.
    pub fn get_node_mut(&mut self, id: u64) -> Option<&mut GraphNode> {
        self.node_id_index
            .get(&id)
            .copied()
            .and_then(move |idx| self.graph.node_weight_mut(idx))
    }

    /// Count the number of relationships connected to a node (both incoming and outgoing).
    pub fn count_node_relationships(&self, id: u64) -> usize {
        if let Some(node_idx) = self.node_id_index.get(&id).copied() {
            self.graph.edges_directed(node_idx, Direction::Outgoing).count()
                + self.graph.edges_directed(node_idx, Direction::Incoming).count()
        } else {
            0
        }
    }

    /// Get an edge by its ID.
    pub fn get_edge(&self, id: u64) -> Option<&GraphEdge> {
        self.edge_id_index
            .get(&id)
            .and_then(|idx| self.graph.edge_weight(*idx))
    }

    /// Get a mutable edge by its ID.
    pub fn get_edge_mut(&mut self, id: u64) -> Option<&mut GraphEdge> {
        self.edge_id_index
            .get(&id)
            .copied()
            .and_then(move |idx| self.graph.edge_weight_mut(idx))
    }

    /// Get the start and end node IDs of a relationship.
    pub fn get_edge_endpoints(&self, edge_id: u64) -> Option<(u64, u64)> {
        let edge_idx = self.edge_id_index.get(&edge_id)?;
        let (start, end) = self.graph.edge_endpoints(*edge_idx)?;
        Some((self.graph[start].id, self.graph[end].id))
    }

    /// Get all nodes in the graph.
    pub fn all_nodes(&self) -> impl Iterator<Item = &GraphNode> {
        self.graph.node_weights()
    }

    /// Get all edges in the graph.
    pub fn all_edges(&self) -> impl Iterator<Item = &GraphEdge> {
        self.graph.edge_weights()
    }

    /// Get all nodes with a specific label.
    pub fn nodes_with_label(&self, label: &str) -> Vec<&GraphNode> {
        self.label_index
            .get(label)
            .map(|indices| {
                indices
                    .iter()
                    .filter_map(|idx| self.graph.node_weight(*idx))
                    .collect()
            })
            .unwrap_or_default()
    }

    /// Get all edges with a specific type.
    pub fn edges_with_type(&self, rel_type: &str) -> Vec<&GraphEdge> {
        self.rel_type_index
            .get(rel_type)
            .map(|indices| {
                indices
                    .iter()
                    .filter_map(|idx| self.graph.edge_weight(*idx))
                    .collect()
            })
            .unwrap_or_default()
    }

    /// Get outgoing edges from a node.
    pub fn outgoing_edges(&self, node_id: u64) -> Vec<(u64, &GraphEdge)> {
        let Some(node_idx) = self.node_id_index.get(&node_id) else {
            return vec![];
        };

        self.graph
            .edges_directed(*node_idx, Direction::Outgoing)
            .map(|edge_ref| {
                let target = self.graph[edge_ref.target()].id;
                (target, edge_ref.weight())
            })
            .collect()
    }

    /// Get incoming edges to a node.
    pub fn incoming_edges(&self, node_id: u64) -> Vec<(u64, &GraphEdge)> {
        let Some(node_idx) = self.node_id_index.get(&node_id) else {
            return vec![];
        };

        self.graph
            .edges_directed(*node_idx, Direction::Incoming)
            .map(|edge_ref| {
                let source = self.graph[edge_ref.source()].id;
                (source, edge_ref.weight())
            })
            .collect()
    }

    /// Get all edges connected to a node (both incoming and outgoing).
    pub fn all_edges_for_node(&self, node_id: u64) -> Vec<(u64, u64, &GraphEdge)> {
        let Some(node_idx) = self.node_id_index.get(&node_id) else {
            return vec![];
        };

        let mut edges = Vec::new();

        for edge_ref in self.graph.edges_directed(*node_idx, Direction::Outgoing) {
            let source = self.graph[edge_ref.source()].id;
            let target = self.graph[edge_ref.target()].id;
            edges.push((source, target, edge_ref.weight()));
        }

        for edge_ref in self.graph.edges_directed(*node_idx, Direction::Incoming) {
            let source = self.graph[edge_ref.source()].id;
            let target = self.graph[edge_ref.target()].id;
            edges.push((source, target, edge_ref.weight()));
        }

        edges
    }

    /// Delete a node by ID. Returns error if the node has relationships.
    pub fn delete_node(&mut self, id: u64) -> ExecutionResult<GraphNode> {
        let node_idx = self
            .node_id_index
            .get(&id)
            .copied()
            .ok_or(ExecutionError::NodeNotFound(id))?;

        // Check for relationships
        let has_edges = self.graph.edges(node_idx).next().is_some();
        if has_edges {
            return Err(ExecutionError::ConstraintViolation(format!(
                "Cannot delete node {} because it still has relationships. Use DETACH DELETE to remove relationships.",
                id
            )));
        }

        // Collect labels first (immutable borrow ends before mutable ops)
        let labels: Vec<String> = self
            .graph
            .node_weight(node_idx)
            .map(|n| n.labels.iter().cloned().collect())
            .unwrap_or_default();

        // Remove from property index (mutable)
        self.remove_from_prop_index(node_idx);

        // Remove from label index
        for label in &labels {
            if let Some(set) = self.label_index.get_mut(label) {
                set.remove(&node_idx);
            }
        }

        // Remove from graph
        let node = self.graph.remove_node(node_idx)
            .ok_or(ExecutionError::NodeNotFound(id))?;
        self.node_id_index.remove(&id);

        Ok(node)
    }

    /// Delete a node and all its relationships.
    pub fn detach_delete_node(&mut self, id: u64) -> ExecutionResult<GraphNode> {
        let node_idx = self
            .node_id_index
            .get(&id)
            .copied()
            .ok_or(ExecutionError::NodeNotFound(id))?;

        // Collect all edges to delete
        let edges_to_delete: Vec<EdgeIndex> = self
            .graph
            .edges_directed(node_idx, Direction::Outgoing)
            .chain(self.graph.edges_directed(node_idx, Direction::Incoming))
            .map(|e| e.id())
            .collect();

        // Delete edges
        for edge_idx in edges_to_delete {
            if let Some(edge) = self.graph.edge_weight(edge_idx) {
                let edge_id = edge.id;
                let rel_type = edge.rel_type.clone();
                self.edge_id_index.remove(&edge_id);
                if let Some(set) = self.rel_type_index.get_mut(&rel_type) {
                    set.remove(&edge_idx);
                }
            }
            self.graph.remove_edge(edge_idx);
        }

        // Collect labels first (immutable borrow ends before mutable ops)
        let labels: Vec<String> = self
            .graph
            .node_weight(node_idx)
            .map(|n| n.labels.iter().cloned().collect())
            .unwrap_or_default();

        // Remove from property index (mutable)
        self.remove_from_prop_index(node_idx);

        // Remove from label index
        for label in &labels {
            if let Some(set) = self.label_index.get_mut(label) {
                set.remove(&node_idx);
            }
        }

        // Remove from graph
        let node = self.graph.remove_node(node_idx)
            .ok_or(ExecutionError::NodeNotFound(id))?;
        self.node_id_index.remove(&id);

        Ok(node)
    }

    /// Delete a relationship by ID.
    pub fn delete_relationship(&mut self, id: u64) -> ExecutionResult<GraphEdge> {
        let edge_idx = self
            .edge_id_index
            .get(&id)
            .copied()
            .ok_or(ExecutionError::RelationshipNotFound(id))?;

        let edge = self.graph.edge_weight(edge_idx).cloned()
            .ok_or(ExecutionError::RelationshipNotFound(id))?;

        // Remove from type index
        if let Some(set) = self.rel_type_index.get_mut(&edge.rel_type) {
            set.remove(&edge_idx);
        }

        // Remove from graph
        self.graph.remove_edge(edge_idx);
        self.edge_id_index.remove(&id);

        Ok(edge)
    }

    /// Add a label to a node.
    pub fn add_label(&mut self, node_id: u64, label: impl Into<String>) -> ExecutionResult<()> {
        let node_idx = self
            .node_id_index
            .get(&node_id)
            .copied()
            .ok_or(ExecutionError::NodeNotFound(node_id))?;

        let label = label.into();

        if let Some(node) = self.graph.node_weight_mut(node_idx) {
            node.labels.insert(label.clone());
        }

        self.label_index.entry(label).or_default().insert(node_idx);

        Ok(())
    }

    /// Remove a label from a node.
    pub fn remove_label(&mut self, node_id: u64, label: &str) -> ExecutionResult<bool> {
        let node_idx = self
            .node_id_index
            .get(&node_id)
            .copied()
            .ok_or(ExecutionError::NodeNotFound(node_id))?;

        let removed = if let Some(node) = self.graph.node_weight_mut(node_idx) {
            node.labels.remove(label)
        } else {
            false
        };

        if removed {
            if let Some(set) = self.label_index.get_mut(label) {
                set.remove(&node_idx);
            }
        }

        Ok(removed)
    }

    /// Set a property on a node.
    pub fn set_node_property(
        &mut self,
        node_id: u64,
        key: impl Into<String>,
        value: PropertyValue,
    ) -> ExecutionResult<()> {
        let node = self
            .get_node_mut(node_id)
            .ok_or(ExecutionError::NodeNotFound(node_id))?;
        node.properties.insert(key.into(), value);
        Ok(())
    }

    /// Remove a property from a node.
    pub fn remove_node_property(
        &mut self,
        node_id: u64,
        key: &str,
    ) -> ExecutionResult<Option<PropertyValue>> {
        let node = self
            .get_node_mut(node_id)
            .ok_or(ExecutionError::NodeNotFound(node_id))?;
        Ok(node.properties.shift_remove(key))
    }

    /// Set a property on a relationship.
    pub fn set_edge_property(
        &mut self,
        edge_id: u64,
        key: impl Into<String>,
        value: PropertyValue,
    ) -> ExecutionResult<()> {
        let edge = self
            .get_edge_mut(edge_id)
            .ok_or(ExecutionError::RelationshipNotFound(edge_id))?;
        edge.properties.insert(key.into(), value);
        Ok(())
    }

    /// Remove a property from a relationship.
    pub fn remove_edge_property(
        &mut self,
        edge_id: u64,
        key: &str,
    ) -> ExecutionResult<Option<PropertyValue>> {
        let edge = self
            .get_edge_mut(edge_id)
            .ok_or(ExecutionError::RelationshipNotFound(edge_id))?;
        Ok(edge.properties.shift_remove(key))
    }

    /// Find the shortest path between two nodes.
    pub fn shortest_path(&self, start_id: u64, end_id: u64) -> Option<Path> {
        use petgraph::algo::dijkstra;

        let start_idx = self.node_id_index.get(&start_id)?;
        let end_idx = self.node_id_index.get(&end_id)?;

        // Use dijkstra with uniform weight
        let predecessors = dijkstra(&self.graph, *start_idx, Some(*end_idx), |_| 1usize);

        if !predecessors.contains_key(end_idx) {
            return None;
        }

        // Reconstruct path using BFS to get actual predecessors
        use std::collections::VecDeque;
        let mut queue = VecDeque::new();
        let mut visited = HashSet::new();
        let mut parent: HashMap<NodeIndex, (NodeIndex, EdgeIndex)> = HashMap::new();

        queue.push_back(*start_idx);
        visited.insert(*start_idx);

        while let Some(current) = queue.pop_front() {
            if current == *end_idx {
                break;
            }

            for edge_ref in self.graph.edges(current) {
                let next = edge_ref.target();
                if !visited.contains(&next) {
                    visited.insert(next);
                    parent.insert(next, (current, edge_ref.id()));
                    queue.push_back(next);
                }
            }
        }

        if !parent.contains_key(end_idx) && start_idx != end_idx {
            return None;
        }

        // Build path
        let mut path_nodes = vec![*end_idx];
        let mut path_edges = vec![];
        let mut current = *end_idx;

        while let Some(&(prev, edge_idx)) = parent.get(&current) {
            path_nodes.push(prev);
            path_edges.push(edge_idx);
            current = prev;
        }

        path_nodes.reverse();
        path_edges.reverse();

        let mut path = Path::new(self.graph[path_nodes[0]].clone());
        for (i, edge_idx) in path_edges.iter().enumerate() {
            let edge = self.graph[*edge_idx].clone();
            let node = self.graph[path_nodes[i + 1]].clone();
            path.extend(edge, node);
        }

        Some(path)
    }

    /// Find all shortest paths between two nodes.
    pub fn all_shortest_paths(&self, start_id: u64, end_id: u64) -> Vec<Path> {
        use std::collections::VecDeque;

        let Some(start_idx) = self.node_id_index.get(&start_id) else {
            return vec![];
        };
        let Some(end_idx) = self.node_id_index.get(&end_id) else {
            return vec![];
        };

        if start_idx == end_idx {
            return vec![Path::new(self.graph[*start_idx].clone())];
        }

        // BFS to find shortest distance and all parents at that distance
        let mut queue = VecDeque::new();
        let mut distances: HashMap<NodeIndex, usize> = HashMap::new();
        let mut parents: HashMap<NodeIndex, Vec<(NodeIndex, EdgeIndex)>> = HashMap::new();

        queue.push_back(*start_idx);
        distances.insert(*start_idx, 0);

        while let Some(current) = queue.pop_front() {
            let current_dist = distances[&current];

            if let Some(&end_dist) = distances.get(end_idx) {
                if current_dist > end_dist {
                    break;
                }
            }

            for edge_ref in self.graph.edges(current) {
                let next = edge_ref.target();
                let next_dist = current_dist + 1;

                match distances.get(&next) {
                    None => {
                        distances.insert(next, next_dist);
                        parents.insert(next, vec![(current, edge_ref.id())]);
                        queue.push_back(next);
                    }
                    Some(&d) if d == next_dist => {
                        if let Some(parent_list) = parents.get_mut(&next) {
                            parent_list.push((current, edge_ref.id()));
                        }
                    }
                    _ => {}
                }
            }
        }

        if !distances.contains_key(end_idx) {
            return vec![];
        }

        // Reconstruct all paths
        fn build_paths(
            graph: &StableDiGraph<GraphNode, GraphEdge>,
            parents: &HashMap<NodeIndex, Vec<(NodeIndex, EdgeIndex)>>,
            start: NodeIndex,
            current: NodeIndex,
            path: &mut Vec<(NodeIndex, Option<EdgeIndex>)>,
            all_paths: &mut Vec<Path>,
        ) {
            path.push((current, None));

            if current == start {
                // Build path from collected nodes
                let last_node_idx = path.last().map(|(idx, _)| *idx).unwrap_or(current);
                let mut new_path = Path::new(graph[last_node_idx].clone());
                for i in (0..path.len() - 1).rev() {
                    if let Some(edge_idx) = path[i].1 {
                        let edge = graph[edge_idx].clone();
                        let node = graph[path[i].0].clone();
                        new_path.extend(edge, node);
                    }
                }
                all_paths.push(new_path);
            } else if let Some(parent_list) = parents.get(&current) {
                for &(parent, edge_idx) in parent_list {
                    if let Some(last) = path.last_mut() {
                        last.1 = Some(edge_idx);
                    }
                    build_paths(graph, parents, start, parent, path, all_paths);
                }
            }

            path.pop();
        }

        let mut all_paths = Vec::new();
        let mut path = Vec::new();
        build_paths(
            &self.graph,
            &parents,
            *start_idx,
            *end_idx,
            &mut path,
            &mut all_paths,
        );

        all_paths
    }

    /// Match nodes that satisfy a predicate.
    pub fn find_nodes<F>(&self, predicate: F) -> Vec<&GraphNode>
    where
        F: Fn(&GraphNode) -> bool,
    {
        self.graph
            .node_weights()
            .filter(|node| predicate(node))
            .collect()
    }

    /// Match edges that satisfy a predicate.
    pub fn find_edges<F>(&self, predicate: F) -> Vec<&GraphEdge>
    where
        F: Fn(&GraphEdge) -> bool,
    {
        self.graph
            .edge_weights()
            .filter(|edge| predicate(edge))
            .collect()
    }

    /// Clear all data from the graph.
    pub fn clear(&mut self) {
        self.graph.clear();
        self.node_id_index.clear();
        self.edge_id_index.clear();
        self.label_index.clear();
        self.rel_type_index.clear();
        self.next_node_id = 1;
        self.next_edge_id = 1;
    }
}

// === GraphBackend trait implementation ===

impl GraphBackend for PropertyGraph {
    type NodeRef<'a> = &'a GraphNode;
    type EdgeRef<'a> = &'a GraphEdge;
    type NodesIter<'a> = Box<dyn Iterator<Item = &'a GraphNode> + 'a>;
    type EdgesIter<'a> = Box<dyn Iterator<Item = &'a GraphEdge> + 'a>;

    fn get_node(&self, id: u64) -> Option<Self::NodeRef<'_>> {
        self.get_node(id)
    }

    fn get_node_mut(&mut self, id: u64) -> Option<&mut GraphNode> {
        self.get_node_mut(id)
    }

    fn all_nodes(&self) -> Self::NodesIter<'_> {
        Box::new(self.all_nodes())
    }

    fn nodes_with_label(&self, label: &str) -> Vec<Self::NodeRef<'_>> {
        self.nodes_with_label(label)
    }

    fn get_edge(&self, id: u64) -> Option<Self::EdgeRef<'_>> {
        self.get_edge(id)
    }

    fn get_edge_mut(&mut self, id: u64) -> Option<&mut GraphEdge> {
        self.get_edge_mut(id)
    }

    fn all_edges(&self) -> Self::EdgesIter<'_> {
        Box::new(self.all_edges())
    }

    fn edges_with_type(&self, rel_type: &str) -> Vec<Self::EdgeRef<'_>> {
        self.edges_with_type(rel_type)
    }

    fn get_edge_endpoints(&self, edge_id: u64) -> Option<(u64, u64)> {
        self.get_edge_endpoints(edge_id)
    }

    fn outgoing_edges(&self, node_id: u64) -> Vec<(u64, Self::EdgeRef<'_>)> {
        self.outgoing_edges(node_id)
    }

    fn incoming_edges(&self, node_id: u64) -> Vec<(u64, Self::EdgeRef<'_>)> {
        self.incoming_edges(node_id)
    }

    fn all_edges_for_node(&self, node_id: u64) -> Vec<(u64, u64, Self::EdgeRef<'_>)> {
        self.all_edges_for_node(node_id)
    }

    fn count_node_relationships(&self, node_id: u64) -> usize {
        self.count_node_relationships(node_id)
    }

    fn shortest_path(&self, start_id: u64, end_id: u64) -> Option<Path> {
        self.shortest_path(start_id, end_id)
    }

    fn all_shortest_paths(&self, start_id: u64, end_id: u64) -> Vec<Path> {
        self.all_shortest_paths(start_id, end_id)
    }

    fn add_existing_node(&mut self, node: GraphNode) {
        self.add_existing_node(node);
    }

    fn create_relationship_with_id(
        &mut self,
        edge_id: u64,
        start_id: u64,
        end_id: u64,
        rel_type: impl Into<String>,
        properties: IndexMap<String, PropertyValue>,
    ) -> ExecutionResult<u64> {
        self.create_relationship_with_id(edge_id, start_id, end_id, rel_type, properties)
    }

    fn create_node(
        &mut self,
        labels: impl IntoIterator<Item = impl Into<String>>,
        properties: IndexMap<String, PropertyValue>,
    ) -> u64 {
        self.create_node(labels, properties).id
    }

    fn create_relationship(
        &mut self,
        start_id: u64,
        end_id: u64,
        rel_type: impl Into<String>,
        properties: IndexMap<String, PropertyValue>,
    ) -> ExecutionResult<u64> {
        self.create_relationship(start_id, end_id, rel_type, properties)
            .map(|edge| edge.id)
    }

    fn delete_node(&mut self, id: u64) -> ExecutionResult<GraphNode> {
        self.delete_node(id)
    }

    fn delete_relationship(&mut self, id: u64) -> ExecutionResult<GraphEdge> {
        self.delete_relationship(id)
    }

    fn detach_delete_node(&mut self, id: u64) -> ExecutionResult<GraphNode> {
        self.detach_delete_node(id)
    }

    fn set_node_property(
        &mut self,
        node_id: u64,
        key: impl Into<String>,
        value: PropertyValue,
    ) -> ExecutionResult<()> {
        self.set_node_property(node_id, key, value)
    }

    fn set_edge_property(
        &mut self,
        edge_id: u64,
        key: impl Into<String>,
        value: PropertyValue,
    ) -> ExecutionResult<()> {
        self.set_edge_property(edge_id, key, value)
    }

    fn remove_node_property(
        &mut self,
        node_id: u64,
        key: &str,
    ) -> ExecutionResult<Option<PropertyValue>> {
        self.remove_node_property(node_id, key)
    }

    fn remove_edge_property(
        &mut self,
        edge_id: u64,
        key: &str,
    ) -> ExecutionResult<Option<PropertyValue>> {
        self.remove_edge_property(edge_id, key)
    }

    fn add_label(&mut self, node_id: u64, label: impl Into<String>) -> ExecutionResult<()> {
        self.add_label(node_id, label)
    }

    fn remove_label(&mut self, node_id: u64, label: &str) -> ExecutionResult<bool> {
        self.remove_label(node_id, label)
    }

    fn node_count(&self) -> usize {
        self.node_count()
    }

    fn edge_count(&self) -> usize {
        self.edge_count()
    }

    fn check_node_constraints(
        &self,
        labels: &[String],
        properties: &IndexMap<String, PropertyValue>,
    ) -> crate::error::ExecutionResult<()> {
        self.check_unique_constraints(labels, properties)
    }

    fn create_index(&mut self, label: &str, property: &str) {
        self.create_index_schema(label, property);
    }

    fn drop_index(&mut self, label: &str, property: &str) {
        self.drop_index_schema(label, property);
    }

    fn create_unique_constraint(&mut self, label: &str, property: &str) {
        self.create_unique_constraint_schema(label, property);
    }

    fn drop_unique_constraint(&mut self, label: &str, property: &str) {
        self.drop_unique_constraint_schema(label, property);
    }

    fn nodes_with_label_property<'a>(
        &'a self,
        label: &str,
        property: &str,
        value: &PropertyValue,
    ) -> Vec<Self::NodeRef<'a>> {
        self.nodes_with_label_property_fast(label, property, value)
    }
}

impl crate::graph::backends::PetgraphAlgorithms for PropertyGraph {
    fn petgraph_inner(&self) -> &StableDiGraph<GraphNode, GraphEdge> {
        &self.graph
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_create_node() {
        let mut graph = PropertyGraph::new();
        let node = graph.create_node(vec!["Person"], IndexMap::new());
        assert_eq!(node.id, 1);
        assert!(node.has_label("Person"));
    }

    #[test]
    fn test_create_relationship() {
        let mut graph = PropertyGraph::new();
        graph.create_node(vec!["Person"], IndexMap::new());
        graph.create_node(vec!["Person"], IndexMap::new());

        let edge = graph
            .create_relationship(1, 2, "KNOWS", IndexMap::new())
            .unwrap();
        assert_eq!(edge.id, 1);
        assert_eq!(edge.rel_type, "KNOWS");
    }

    #[test]
    fn test_get_node() {
        let mut graph = PropertyGraph::new();
        let mut props = IndexMap::new();
        props.insert("name".to_string(), PropertyValue::String("Alice".to_string()));
        graph.create_node(vec!["Person"], props);

        let node = graph.get_node(1).unwrap();
        assert_eq!(node.get_property("name"), Some(&PropertyValue::String("Alice".to_string())));
    }

    #[test]
    fn test_nodes_with_label() {
        let mut graph = PropertyGraph::new();
        graph.create_node(vec!["Person"], IndexMap::new());
        graph.create_node(vec!["Person"], IndexMap::new());
        graph.create_node(vec!["Company"], IndexMap::new());

        let people = graph.nodes_with_label("Person");
        assert_eq!(people.len(), 2);

        let companies = graph.nodes_with_label("Company");
        assert_eq!(companies.len(), 1);
    }

    #[test]
    fn test_delete_node() {
        let mut graph = PropertyGraph::new();
        graph.create_node(vec!["Person"], IndexMap::new());

        assert!(graph.get_node(1).is_some());
        graph.delete_node(1).unwrap();
        assert!(graph.get_node(1).is_none());
    }

    #[test]
    fn test_delete_node_with_relationships_fails() {
        let mut graph = PropertyGraph::new();
        graph.create_node(vec!["Person"], IndexMap::new());
        graph.create_node(vec!["Person"], IndexMap::new());
        graph.create_relationship(1, 2, "KNOWS", IndexMap::new()).unwrap();

        let result = graph.delete_node(1);
        assert!(result.is_err());
    }

    #[test]
    fn test_detach_delete_node() {
        let mut graph = PropertyGraph::new();
        graph.create_node(vec!["Person"], IndexMap::new());
        graph.create_node(vec!["Person"], IndexMap::new());
        graph.create_relationship(1, 2, "KNOWS", IndexMap::new()).unwrap();

        graph.detach_delete_node(1).unwrap();
        assert!(graph.get_node(1).is_none());
        assert!(graph.get_edge(1).is_none());
    }

    #[test]
    fn test_shortest_path() {
        let mut graph = PropertyGraph::new();
        graph.create_node(vec!["Node"], IndexMap::new()); // 1
        graph.create_node(vec!["Node"], IndexMap::new()); // 2
        graph.create_node(vec!["Node"], IndexMap::new()); // 3
        graph.create_node(vec!["Node"], IndexMap::new()); // 4

        graph.create_relationship(1, 2, "NEXT", IndexMap::new()).unwrap();
        graph.create_relationship(2, 3, "NEXT", IndexMap::new()).unwrap();
        graph.create_relationship(3, 4, "NEXT", IndexMap::new()).unwrap();
        graph.create_relationship(1, 4, "SKIP", IndexMap::new()).unwrap(); // Direct route

        let path = graph.shortest_path(1, 4).unwrap();
        assert_eq!(path.length(), 1); // Direct path is shortest
    }

    #[test]
    fn test_outgoing_edges() {
        let mut graph = PropertyGraph::new();
        graph.create_node(vec!["Person"], IndexMap::new()); // 1
        graph.create_node(vec!["Person"], IndexMap::new()); // 2
        graph.create_node(vec!["Person"], IndexMap::new()); // 3

        graph.create_relationship(1, 2, "KNOWS", IndexMap::new()).unwrap();
        graph.create_relationship(1, 3, "KNOWS", IndexMap::new()).unwrap();

        let edges = graph.outgoing_edges(1);
        assert_eq!(edges.len(), 2);
    }
}
