use std::error::Error;
use std::fmt::{Display, Formatter};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LayoutError {
    InvalidNodeIndex {
        edge_index: usize,
        node_index: usize,
        node_count: usize,
    },
    SelfLoop {
        edge_index: usize,
        node: usize,
    },
    DuplicateEdge {
        edge_index: usize,
        source: usize,
        target: usize,
    },
    CycleDetected,
    InvalidHierarchyEdge {
        edge_index: usize,
        source: usize,
        target: usize,
        source_level: usize,
        target_level: usize,
    },
}

impl Display for LayoutError {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            LayoutError::InvalidNodeIndex {
                edge_index,
                node_index,
                node_count,
            } => write!(
                f,
                "edge {} references node {} but graph only has {} nodes",
                edge_index, node_index, node_count
            ),
            LayoutError::SelfLoop { edge_index, node } => {
                write!(f, "edge {} is a self-loop on node {}", edge_index, node)
            }
            LayoutError::DuplicateEdge {
                edge_index,
                source,
                target,
            } => write!(
                f,
                "edge {} duplicates existing directed edge {} -> {}",
                edge_index, source, target
            ),
            LayoutError::CycleDetected => write!(f, "graph must be a directed acyclic graph"),
            LayoutError::InvalidHierarchyEdge {
                edge_index,
                source,
                target,
                source_level,
                target_level,
            } => write!(
                f,
                "edge {} ({} -> {}) violates hierarchy levels {} -> {}",
                edge_index, source, target, source_level, target_level
            ),
        }
    }
}

impl Error for LayoutError {}
