//! Topology and solver error types.

use thiserror::Error;

/// Errors that can occur during topology validation or system construction.
#[derive(Error, Debug, Clone, PartialEq)]
pub enum TopologyError {
    /// A node has no edges (isolated/dangling node).
    #[error("Isolated node at index {node_index}: all components must be connected")]
    IsolatedNode {
        /// Index of the isolated node in the graph
        node_index: usize,
    },

    /// Not all ports are connected (reserved for Story 3.2 port validation).
    #[error("Unconnected ports: {message}")]
    #[allow(dead_code)]
    UnconnectedPorts {
        /// Description of which ports are unconnected
        message: String,
    },

    /// Topology validation failed for another reason.
    #[error("Invalid topology: {message}")]
    #[allow(dead_code)]
    InvalidTopology {
        /// Description of the validation failure
        message: String,
    },

    /// Attempted to connect nodes in different circuits via a flow edge.
    /// Flow edges must connect nodes within the same circuit. Cross-circuit
    /// thermal coupling is handled in Story 3.4.
    #[error("Cross-circuit connection not allowed: source circuit {source_circuit}, target circuit {target_circuit}. Flow edges connect only nodes within the same circuit")]
    CrossCircuitConnection {
        /// Circuit ID of the source node
        source_circuit: u16,
        /// Circuit ID of the target node
        target_circuit: u16,
    },

    /// Too many circuits requested. Maximum is 5 (circuit IDs 0..=4).
    #[error("Too many circuits: requested {requested}, maximum is 5")]
    TooManyCircuits {
        /// The requested circuit ID that exceeded the limit
        requested: u16,
    },

    /// Attempted to add thermal coupling with a circuit that doesn't exist.
    #[error(
        "Invalid circuit for thermal coupling: circuit {circuit_id} does not exist in the system"
    )]
    InvalidCircuitForCoupling {
        /// The circuit ID that was referenced but doesn't exist
        circuit_id: u16,
    },

    /// System equation/unknown count is not square (DoF imbalance).
    ///
    /// A real-machine simulation requires `n_equations == n_unknowns`. Fixing a
    /// quantity without freeing another (or dropping a residual) is rejected here.
    #[error("System DoF imbalance: {message}")]
    DofImbalance {
        /// Human-readable ledger summary.
        message: String,
    },
}

/// Error when adding an edge with port validation.
///
/// Combines port validation errors ([`entropyk_components::ConnectionError`]) and topology errors
/// ([`TopologyError`]) such as cross-circuit connection attempts.
#[derive(Error, Debug, Clone, PartialEq)]
pub enum AddEdgeError {
    /// Port validation failed (fluid, pressure, enthalpy mismatch).
    #[error(transparent)]
    Connection(#[from] entropyk_components::ConnectionError),

    /// Topology validation failed (e.g. cross-circuit connection).
    #[error(transparent)]
    Topology(#[from] TopologyError),
}

/// Thermodynamic simulation and system errors.
///
/// This error type encompasses all errors that can occur during system
/// serialization, deserialization, and simulation operations.
#[derive(Error, Debug, Clone, PartialEq)]
pub enum ThermoError {
    /// JSON serialization failed.
    #[error("Serialization failed: {0}")]
    SerializationError(String),

    /// JSON deserialization failed.
    #[error("Deserialization failed: {0}")]
    DeserializationError(String),

    /// Schema version mismatch between serialized data and current code.
    #[error("Version mismatch: expected '{expected}', found '{found}'")]
    VersionMismatch {
        /// Expected schema version
        expected: String,
        /// Found schema version in JSON
        found: String,
    },

    /// Required fluid backend is not available.
    #[error(
        "Fluid backend '{backend_name}' is not available. Required version: {required_version}"
    )]
    BackendUnavailable {
        /// Name of the missing backend
        backend_name: String,
        /// Required version
        required_version: String,
    },

    /// I/O error during file operations.
    #[error("I/O error: {0}")]
    IoError(String),
}
