//! Hosting Error Types
//!
//! Error definitions for the Synor Hosting system.

use thiserror::Error;

/// Hosting errors
#[derive(Debug, Error)]
pub enum Error {
    /// Invalid name format
    #[error("invalid name: {0}")]
    InvalidName(String),

    /// Name is reserved
    #[error("name '{0}' is reserved")]
    ReservedName(String),

    /// Name is too similar to a reserved name (confusable)
    #[error("name '{0}' is too similar to reserved name '{1}'")]
    ConfusableName(String, String),

    /// Name not found in registry
    #[error("name '{0}' not found")]
    NameNotFound(String),

    /// Name already registered
    #[error("name '{0}' is already registered")]
    NameAlreadyRegistered(String),

    /// Name is already taken
    #[error("name '{0}' is already taken")]
    NameTaken(String),

    /// Invalid operation
    #[error("invalid operation: {0}")]
    InvalidOperation(String),

    /// Name has expired
    #[error("name '{0}' has expired")]
    NameExpired(String),

    /// Not the owner of this name
    #[error("not the owner of this name")]
    NotOwner,

    /// Domain already linked to another name
    #[error("domain '{0}' is already linked to another name")]
    DomainAlreadyLinked(String),

    /// Domain not verified
    #[error("domain '{0}' is not verified")]
    DomainNotVerified(String),

    /// Domain verification pending
    #[error("domain '{0}' verification is pending")]
    DomainVerificationPending(String),

    /// Domain verification expired
    #[error("domain '{0}' verification has expired")]
    DomainVerificationExpired(String),

    /// Domain not found
    #[error("domain '{0}' not found")]
    DomainNotFound(String),

    /// Domain verification failed
    #[error("verification failed for domain '{0}': {1}")]
    VerificationFailed(String, String),

    /// Invalid domain format
    #[error("invalid domain: {0}")]
    InvalidDomain(String),

    /// Unknown host
    #[error("unknown host: {0}")]
    UnknownHost(String),

    /// Redirect response
    #[error("redirect to {to} with status {status}")]
    Redirect {
        /// Target URL
        to: String,
        /// HTTP status code
        status: u16,
    },

    /// Configuration error
    #[error("configuration error: {0}")]
    Config(String),

    /// Storage error
    #[error("storage error: {0}")]
    Storage(String),

    /// DNS resolution error
    #[error("DNS error: {0}")]
    Dns(String),

    /// IO error
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),

    /// JSON parsing error
    #[error("JSON error: {0}")]
    Json(#[from] serde_json::Error),
}

/// Result type alias
pub type Result<T> = std::result::Result<T, Error>;

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

    #[test]
    fn test_error_display() {
        let err = Error::InvalidName("bad-name!".to_string());
        assert_eq!(err.to_string(), "invalid name: bad-name!");

        let err = Error::NameNotFound("myapp".to_string());
        assert_eq!(err.to_string(), "name 'myapp' not found");

        let err = Error::Redirect {
            to: "https://example.com".to_string(),
            status: 301,
        };
        assert!(err.to_string().contains("redirect"));
    }
}
