//! Error types for LightningStor

use thiserror::Error;

/// Result type for LightningStor operations
pub type Result<T> = std::result::Result<T, Error>;

/// Error types for object storage operations
#[derive(Debug, Error)]
pub enum Error {
    #[error("bucket not found: {0}")]
    BucketNotFound(String),

    #[error("bucket already exists: {0}")]
    BucketAlreadyExists(String),

    #[error("bucket not empty: {0}")]
    BucketNotEmpty(String),

    #[error("object not found: {bucket}/{key}")]
    ObjectNotFound { bucket: String, key: String },

    #[error("invalid bucket name: {0}")]
    InvalidBucketName(String),

    #[error("invalid object key: {0}")]
    InvalidObjectKey(String),

    #[error("access denied: {0}")]
    AccessDenied(String),

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

    #[error("upload not found: {0}")]
    UploadNotFound(String),

    #[error("invalid part: {0}")]
    InvalidPart(String),

    #[error("entity too large: max {max_bytes} bytes, got {actual_bytes}")]
    EntityTooLarge { max_bytes: u64, actual_bytes: u64 },

    #[error("precondition failed: {0}")]
    PreconditionFailed(String),

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

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

impl Error {
    /// Returns the S3 error code for this error
    pub fn s3_error_code(&self) -> &'static str {
        match self {
            Error::BucketNotFound(_) => "NoSuchBucket",
            Error::BucketAlreadyExists(_) => "BucketAlreadyExists",
            Error::BucketNotEmpty(_) => "BucketNotEmpty",
            Error::ObjectNotFound { .. } => "NoSuchKey",
            Error::InvalidBucketName(_) => "InvalidBucketName",
            Error::InvalidObjectKey(_) => "InvalidArgument",
            Error::AccessDenied(_) => "AccessDenied",
            Error::InvalidArgument(_) => "InvalidArgument",
            Error::UploadNotFound(_) => "NoSuchUpload",
            Error::InvalidPart(_) => "InvalidPart",
            Error::EntityTooLarge { .. } => "EntityTooLarge",
            Error::PreconditionFailed(_) => "PreconditionFailed",
            Error::StorageError(_) => "InternalError",
            Error::Internal(_) => "InternalError",
        }
    }

    /// Returns the HTTP status code for this error
    pub fn http_status(&self) -> u16 {
        match self {
            Error::BucketNotFound(_) => 404,
            Error::BucketAlreadyExists(_) => 409,
            Error::BucketNotEmpty(_) => 409,
            Error::ObjectNotFound { .. } => 404,
            Error::InvalidBucketName(_) => 400,
            Error::InvalidObjectKey(_) => 400,
            Error::AccessDenied(_) => 403,
            Error::InvalidArgument(_) => 400,
            Error::UploadNotFound(_) => 404,
            Error::InvalidPart(_) => 400,
            Error::EntityTooLarge { .. } => 400,
            Error::PreconditionFailed(_) => 412,
            Error::StorageError(_) => 500,
            Error::Internal(_) => 500,
        }
    }
}
