//! Domain-level validation errors.
//!
//! These errors are raised by validating constructors (`new`/`try_new`) when an
//! invariant documented in `ARCHITECTURE.md` §3.2 is violated. They are pure
//! data — no I/O, no platform coupling.

use thiserror::Error;

/// Error raised when an entity or value object invariant is violated at
/// construction time.
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum DomainError {
    /// A required string field was empty.
    #[error("field `{field}` must not be empty")]
    EmptyField {
        /// Name of the offending field.
        field: &'static str,
    },

    /// A path that must be absolute was relative.
    #[error("path `{path}` must be absolute")]
    PathNotAbsolute {
        /// The offending path.
        path: String,
    },

    /// A path that must be relative was absolute, or escaped its root via `..`.
    #[error("path `{path}` must be relative and must not contain `..`")]
    PathNotRelativeSafe {
        /// The offending path.
        path: String,
    },

    /// An environment variable name was not a valid identifier.
    #[error("`{value}` is not a valid environment variable identifier")]
    InvalidEnvVar {
        /// The offending value.
        value: String,
    },

    /// An SSH port was outside the valid `1..=65535` range.
    #[error("ssh port must be in 1..=65535, got {port}")]
    InvalidPort {
        /// The offending port.
        port: u32,
    },

    /// A PTY dimension was zero.
    #[error("pty size must have rows>0 and cols>0, got rows={rows} cols={cols}")]
    InvalidPtySize {
        /// Requested rows.
        rows: u16,
        /// Requested cols.
        cols: u16,
    },

    /// `synchronized == true` requires an agent originating from a template.
    #[error("a synchronized agent must originate from a template")]
    SyncRequiresTemplate,

    /// A manifest entry was inconsistent (e.g. synchronized without template metadata).
    #[error("manifest entry inconsistent: {reason}")]
    InconsistentManifest {
        /// Human-readable reason.
        reason: String,
    },

    /// A memory slug was not valid kebab-case (`[a-z0-9-]`, non-empty).
    #[error("`{value}` is not a valid kebab-case slug")]
    InvalidSlug {
        /// The offending value.
        value: String,
    },

    /// A generic invariant violation with an explanatory message.
    #[error("invariant violated: {0}")]
    Invariant(String),
}
