use std::io;
use std::path::PathBuf;

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

#[derive(Debug, thiserror::Error)]
pub enum AppError {
    #[error("configuration error: {0}")]
    Config(String),

    #[error("missing environment variable: {0}")]
    MissingEnv(String),

    #[error("io error at {path}: {source}")]
    Io {
        path: PathBuf,
        #[source]
        source: io::Error,
    },

    #[error("tool '{tool}': {message}")]
    Tool { tool: String, message: String },

    #[error("extension `{extension_name}` cancelled the action{}", reason.as_ref().map(|r| format!(": {r}")).unwrap_or_default())]
    HookCancelled {
        extension_name: String,
        reason: Option<String>,
    },

    #[error("agent loop error: {0}")]
    AgentLoop(#[from] motosan_agent_loop::AgentError),

    #[error("permissions policy: {0}")]
    Policy(#[from] crate::permissions::PolicyError),

    #[error("llm error: {0}")]
    Llm(String),
}

impl AppError {
    pub fn io(path: impl Into<PathBuf>, source: io::Error) -> Self {
        Self::Io {
            path: path.into(),
            source,
        }
    }

    pub fn tool(tool: impl Into<String>, message: impl Into<String>) -> Self {
        Self::Tool {
            tool: tool.into(),
            message: message.into(),
        }
    }
}
