use thiserror::Error;

#[derive(Error, Debug)]
pub enum AgentError {
    #[error("openai error: {0}")]
    OpenAi(String),

    #[error("qdrant error: {0}")]
    Qdrant(String),

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

    /// The task exceeded its timeout limit.
    #[error("task {task_id} timed out after {seconds}s")]
    Timeout { task_id: i64, seconds: u64 },

    /// The agent has been rate-limited; retry after the indicated delay.
    #[error("rate limited, retry after {retry_after_secs}s")]
    RateLimited { retry_after_secs: u64 },

    /// A transient error that can be retried.
    #[error("retryable error (attempt {attempt}): {message}")]
    Retryable { attempt: u32, message: String },

    /// The requested tool is not registered in the tool registry.
    #[error("tool not found: {tool}")]
    ToolNotFound { tool: String },

    /// A tool execution failed.
    #[error("tool '{tool}' execution failed: {cause}")]
    ToolExecutionFailed { tool: String, cause: String },

    /// The request contains invalid input.
    #[error("invalid input in '{field}': {reason}")]
    InvalidInput { field: String, reason: String },
}

pub type Result<T> = std::result::Result<T, AgentError>;

impl From<async_openai::error::OpenAIError> for AgentError {
    fn from(e: async_openai::error::OpenAIError) -> Self {
        AgentError::OpenAi(e.to_string())
    }
}

impl From<qdrant_client::QdrantError> for AgentError {
    fn from(e: qdrant_client::QdrantError) -> Self {
        AgentError::Qdrant(e.to_string())
    }
}

impl From<sea_orm::DbErr> for AgentError {
    fn from(e: sea_orm::DbErr) -> Self {
        AgentError::Internal(e.to_string())
    }
}
