#[derive(Debug, thiserror::Error)]
pub enum ChannelError {
    #[error("unauthorized")]
    Unauthorized,
    #[error("token invalid or expired")]
    TokenInvalidOrExpired,
    #[error("renewal limit exceeded")]
    RenewalLimitExceeded,
    #[error("rate limit exceeded")]
    RateLimitExceeded,
    #[error("room not found")]
    RoomNotFound,
    #[error("user not found")]
    UserNotFound,
    #[error("access denied")]
    AccessDenied,
    #[error("validation failed: {0}")]
    Validation(String),
    #[error("internal error: {0}")]
    Internal(String),
    #[error("database failed: {0}")]
    Database(#[from] db::sqlx::Error),
    #[error("cache failed: {0}")]
    Cache(#[from] cache::CacheError),
    #[error("socket.io failed: {0}")]
    SocketIo(#[from] socketio::SocketIoError),
    #[error("serialization failed: {0}")]
    Serialization(#[from] serde_json::Error),
    #[error("redis failed: {0}")]
    Redis(#[from] redis::RedisError),
    #[error("storage failed: {0}")]
    Storage(#[from] storage::StorageError),
}

impl ChannelError {
    pub fn ws_error_code(&self) -> (u16, &'static str) {
        match self {
            ChannelError::Unauthorized => (401, "unauthorized"),
            ChannelError::TokenInvalidOrExpired => (401, "token_invalid"),
            ChannelError::AccessDenied => (403, "access_denied"),
            ChannelError::Validation(_) => (422, "validation_failed"),
            ChannelError::RateLimitExceeded => (429, "rate_limit_exceeded"),
            ChannelError::RoomNotFound => (404, "not_found"),
            ChannelError::UserNotFound => (404, "user_not_found"),
            ChannelError::RenewalLimitExceeded => (429, "renewal_limit"),
            ChannelError::Internal(_) => (500, "internal_error"),
            ChannelError::Database(_) => (500, "internal_error"),
            ChannelError::Cache(_) => (500, "internal_error"),
            ChannelError::SocketIo(_) => (500, "internal_error"),
            ChannelError::Serialization(_) => (500, "internal_error"),
            ChannelError::Redis(_) => (500, "internal_error"),
            ChannelError::Storage(_) => (500, "internal_error"),
        }
    }

    pub fn to_ws_error(&self) -> crate::http::out_event::WsError {
        let (code, error_type) = self.ws_error_code();
        crate::http::out_event::WsError {
            code: code as i32,
            error: error_type.to_string(),
            message: self.to_string(),
        }
    }
}

pub type ChannelResult<T> = Result<T, ChannelError>;
