//! Common error types for Veza services
//! 
//! This module provides standardized error handling across all Veza services.

use serde::{Deserialize, Serialize};
use thiserror::Error;

pub mod server;

/// Common error type for Veza services
#[derive(Debug, Error, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", content = "message")]
pub enum CommonError {
    /// Resource not found
    #[error("Not found: {0}")]
    NotFound(String),
    
    /// Validation error
    #[error("Validation error: {0}")]
    ValidationError(String),
    
    /// Internal server error
    #[error("Internal error: {0}")]
    InternalError(String),
    
    /// Authentication error
    #[error("Authentication error: {0}")]
    AuthenticationError(String),
    
    /// Authorization error
    #[error("Authorization error: {0}")]
    AuthorizationError(String),
    
    /// Invalid input data
    #[error("Invalid input: {0}")]
    InvalidInput(String),
    
    /// Conflict error (e.g., duplicate resource)
    #[error("Conflict: {0}")]
    Conflict(String),
    
    /// Rate limit exceeded
    #[error("Rate limit exceeded: {0}")]
    RateLimitExceeded(String),
    
    /// IO error
    #[error("IO error: {0}")]
    IoError(String),
    
    /// Serialization/deserialization error
    #[error("Serialization error: {0}")]
    SerializationError(String),
}

/// Error code for each error type
impl CommonError {
    /// Get the error code for this error
    pub fn code(&self) -> &'static str {
        match self {
            CommonError::NotFound(_) => "NOT_FOUND",
            CommonError::ValidationError(_) => "VALIDATION_ERROR",
            CommonError::InternalError(_) => "INTERNAL_ERROR",
            CommonError::AuthenticationError(_) => "AUTHENTICATION_ERROR",
            CommonError::AuthorizationError(_) => "AUTHORIZATION_ERROR",
            CommonError::InvalidInput(_) => "INVALID_INPUT",
            CommonError::Conflict(_) => "CONFLICT",
            CommonError::RateLimitExceeded(_) => "RATE_LIMIT_EXCEEDED",
            CommonError::IoError(_) => "IO_ERROR",
            CommonError::SerializationError(_) => "SERIALIZATION_ERROR",
        }
    }
    
    /// Get the HTTP status code for this error
    pub fn http_status_code(&self) -> u16 {
        match self {
            CommonError::NotFound(_) => 404,
            CommonError::ValidationError(_) => 400,
            CommonError::InternalError(_) => 500,
            CommonError::AuthenticationError(_) => 401,
            CommonError::AuthorizationError(_) => 403,
            CommonError::InvalidInput(_) => 400,
            CommonError::Conflict(_) => 409,
            CommonError::RateLimitExceeded(_) => 429,
            CommonError::IoError(_) => 500,
            CommonError::SerializationError(_) => 400,
        }
    }
    
    /// Get the error message
    pub fn message(&self) -> &str {
        match self {
            CommonError::NotFound(msg) => msg,
            CommonError::ValidationError(msg) => msg,
            CommonError::InternalError(msg) => msg,
            CommonError::AuthenticationError(msg) => msg,
            CommonError::AuthorizationError(msg) => msg,
            CommonError::InvalidInput(msg) => msg,
            CommonError::Conflict(msg) => msg,
            CommonError::RateLimitExceeded(msg) => msg,
            CommonError::IoError(msg) => msg,
            CommonError::SerializationError(msg) => msg,
        }
    }
    
    /// Check if this error should be logged
    pub fn should_log(&self) -> bool {
        match self {
            CommonError::InternalError(_) | CommonError::IoError(_) => true,
            _ => false,
        }
    }
}

/// Result type alias for CommonError
pub type CommonResult<T> = Result<T, CommonError>;

/// Conversion from std::io::Error
impl From<std::io::Error> for CommonError {
    fn from(err: std::io::Error) -> Self {
        CommonError::IoError(err.to_string())
    }
}

/// Conversion from serde_json::Error
impl From<serde_json::Error> for CommonError {
    fn from(err: serde_json::Error) -> Self {
        CommonError::SerializationError(err.to_string())
    }
}

/// Conversion from uuid::Error
impl From<uuid::Error> for CommonError {
    fn from(err: uuid::Error) -> Self {
        CommonError::ValidationError(format!("Invalid UUID: {}", err))
    }
}

/// Conversion from chrono::ParseError
impl From<chrono::ParseError> for CommonError {
    fn from(err: chrono::ParseError) -> Self {
        CommonError::ValidationError(format!("Invalid date format: {}", err))
    }
}

/// JSON representation of the error for API responses
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ErrorResponse {
    pub error: String,
    pub code: String,
    pub status: u16,
    pub message: String,
}

impl From<&CommonError> for ErrorResponse {
    fn from(err: &CommonError) -> Self {
        ErrorResponse {
            error: err.code().to_string(),
            code: err.code().to_string(),
            status: err.http_status_code(),
            message: err.message().to_string(),
        }
    }
}

impl From<CommonError> for ErrorResponse {
    fn from(err: CommonError) -> Self {
        ErrorResponse::from(&err)
    }
}

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

    #[test]
    fn test_error_codes() {
        assert_eq!(CommonError::NotFound("test".to_string()).code(), "NOT_FOUND");
        assert_eq!(CommonError::ValidationError("test".to_string()).code(), "VALIDATION_ERROR");
        assert_eq!(CommonError::InternalError("test".to_string()).code(), "INTERNAL_ERROR");
    }

    #[test]
    fn test_http_status_codes() {
        assert_eq!(CommonError::NotFound("test".to_string()).http_status_code(), 404);
        assert_eq!(CommonError::ValidationError("test".to_string()).http_status_code(), 400);
        assert_eq!(CommonError::InternalError("test".to_string()).http_status_code(), 500);
        assert_eq!(CommonError::AuthenticationError("test".to_string()).http_status_code(), 401);
        assert_eq!(CommonError::AuthorizationError("test".to_string()).http_status_code(), 403);
        assert_eq!(CommonError::Conflict("test".to_string()).http_status_code(), 409);
        assert_eq!(CommonError::RateLimitExceeded("test".to_string()).http_status_code(), 429);
    }

    #[test]
    fn test_error_message() {
        let err = CommonError::NotFound("Resource not found".to_string());
        assert_eq!(err.message(), "Resource not found");
    }

    #[test]
    fn test_error_should_log() {
        assert!(CommonError::InternalError("test".to_string()).should_log());
        assert!(CommonError::IoError("test".to_string()).should_log());
        assert!(!CommonError::NotFound("test".to_string()).should_log());
        assert!(!CommonError::ValidationError("test".to_string()).should_log());
    }

    #[test]
    fn test_from_io_error() {
        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "File not found");
        let common_err: CommonError = io_err.into();
        match common_err {
            CommonError::IoError(msg) => assert!(msg.contains("File not found")),
            _ => panic!("Expected IoError"),
        }
    }

    #[test]
    fn test_from_serde_json_error() {
        let json_err = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
        let common_err: CommonError = json_err.into();
        match common_err {
            CommonError::SerializationError(_) => {},
            _ => panic!("Expected SerializationError"),
        }
    }

    #[test]
    fn test_error_response() {
        let err = CommonError::NotFound("Resource not found".to_string());
        let response: ErrorResponse = (&err).into();
        assert_eq!(response.error, "NOT_FOUND");
        assert_eq!(response.code, "NOT_FOUND");
        assert_eq!(response.status, 404);
        assert_eq!(response.message, "Resource not found");
    }

    #[test]
    fn test_error_serialize() {
        let err = CommonError::ValidationError("Invalid input".to_string());
        let json = serde_json::to_string(&err).unwrap();
        assert!(json.contains("ValidationError"));
        assert!(json.contains("Invalid input"));
    }

    #[test]
    fn test_error_deserialize() {
        let json = r#"{"type":"ValidationError","message":"Invalid input"}"#;
        let err: CommonError = serde_json::from_str(json).unwrap();
        match err {
            CommonError::ValidationError(msg) => assert_eq!(msg, "Invalid input"),
            _ => panic!("Expected ValidationError"),
        }
    }

    #[test]
    fn test_display() {
        let err = CommonError::NotFound("User not found".to_string());
        let display = format!("{}", err);
        assert!(display.contains("Not found"));
        assert!(display.contains("User not found"));
    }

    #[test]
    fn test_result_type() {
        fn example_function() -> CommonResult<i32> {
            Ok(42)
        }
        
        fn example_error() -> CommonResult<i32> {
            Err(CommonError::NotFound("Not found".to_string()))
        }
        
        assert!(example_function().is_ok());
        assert!(example_error().is_err());
    }
}

