//! Error types for the openCypher parser and executor.

use thiserror::Error;

use crate::parser::Rule;

/// Errors that can occur during parsing.
#[derive(Error, Debug)]
pub enum ParseError {
    #[error("Parse error: {0}")]
    Pest(#[from] pest::error::Error<Rule>),

    #[error("Unexpected rule: expected {expected}, found {found}")]
    UnexpectedRule { expected: String, found: String },

    #[error("Missing required element: {0}")]
    MissingElement(String),

    #[error("Integer overflow: {0}")]
    IntegerOverflow(String),
}

/// Errors that can occur during query execution.
#[derive(Error, Debug)]
pub enum ExecutionError {
    #[error("Parse error: {0}")]
    Parse(#[from] ParseError),

    #[error("Type error: {0}")]
    Type(String),

    #[error("Cannot apply operator {operator} to {left_type} and {right_type}")]
    InvalidOperandTypes {
        operator: String,
        left_type: String,
        right_type: String,
    },

    #[error("Expected {expected}, got {actual}")]
    TypeMismatch { expected: String, actual: String },

    #[error("Cannot compare {left_type} and {right_type}")]
    IncomparableTypes {
        left_type: String,
        right_type: String,
    },

    #[error("Invalid argument: {0}")]
    InvalidArgument(String),

    #[error("Unknown function: {0}")]
    UnknownFunction(String),

    #[error("Unknown procedure: {0}")]
    UnknownProcedure(String),

    #[error("Variable not found: {0}")]
    VariableNotFound(String),

    #[error("Property not found: {0}")]
    PropertyNotFound(String),

    #[error("Label not found: {0}")]
    LabelNotFound(String),

    #[error("Node not found: {0}")]
    NodeNotFound(u64),

    #[error("Relationship not found: {0}")]
    RelationshipNotFound(u64),

    #[error("Constraint violation: {0}")]
    ConstraintViolation(String),

    #[error("Delete error: {0}")]
    DeleteError(String),

    #[error("Division by zero")]
    DivisionByZero,

    #[error("Invalid regex pattern: {0}")]
    InvalidRegex(String),

    #[error("Index out of bounds: {index} for size {size}")]
    IndexOutOfBounds { index: i64, size: usize },

    #[error("Aggregation error: {0}")]
    AggregationError(String),

    #[error("Path error: {0}")]
    PathError(String),

    #[error("Procedure not found: {0}")]
    ProcedureNotFound(String),

    #[error("Internal error: {0}")]
    Internal(String),

    #[error("Cannot access property '{property}' on {value_type}")]
    InvalidPropertyAccess {
        property: String,
        value_type: String,
    },

    #[error("Cannot index {value_type} with {index_type}")]
    InvalidIndexType {
        value_type: String,
        index_type: String,
    },

    #[error("Expected {expected} arguments for function '{function}', got {actual}")]
    WrongArgumentCount {
        function: String,
        expected: String,
        actual: usize,
    },

    #[error("Pattern matching failed: {0}")]
    PatternMatchFailed(String),

    #[error("Graph operation failed: {0}")]
    GraphOperationFailed(String),

    #[error("Partition mismatch: {0}")]
    PartitionMismatch(String),
}

/// Result type for query execution.
pub type ExecutionResult<T> = Result<T, ExecutionError>;

/// A unified error type for the library.
#[derive(Error, Debug)]
pub enum CypherError {
    #[error("{0}")]
    Parse(#[from] ParseError),

    #[error("{0}")]
    Execution(#[from] ExecutionError),
}

/// Unified result type.
pub type CypherResult<T> = Result<T, CypherError>;
