//! Tool call and result types.

use serde::{Deserialize, Serialize};

/// A single tool invocation requested by the AI model.
#[derive(Debug, Clone)]
pub struct ToolCall {
    pub id: String,
    pub name: String,
    pub arguments: String,
}

impl ToolCall {
    pub fn arguments_json(&self) -> serde_json::Result<serde_json::Value> {
        serde_json::from_str(&self.arguments)
    }

    pub fn parse_args<T: serde::de::DeserializeOwned>(&self) -> serde_json::Result<T> {
        serde_json::from_str(&self.arguments)
    }
}

/// The result of executing a tool call.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ToolResult {
    /// Successful result with a JSON value.
    Ok(serde_json::Value),
    /// Error result with an error message.
    Error(String),
}

impl ToolResult {
    pub fn ok<T: Serialize>(value: T) -> Self {
        Self::Ok(serde_json::to_value(value).unwrap_or(serde_json::Value::Null))
    }

    pub fn error(message: impl Into<String>) -> Self {
        Self::Error(message.into())
    }

    pub fn is_error(&self) -> bool {
        matches!(self, Self::Error(_))
    }
}

/// Errors that can occur during tool execution.
#[derive(Debug, thiserror::Error)]
pub enum ToolError {
    #[error("tool not found: {0}")]
    NotFound(String),

    #[error("argument parse error: {0}")]
    ParseError(String),

    #[error("execution error: {0}")]
    ExecutionError(String),

    #[error("recursion limit exceeded (max depth: {max_depth})")]
    RecursionLimitExceeded { max_depth: u32 },

    #[error("max tool calls exceeded: {0}")]
    MaxToolCallsExceeded(usize),

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

impl ToolError {
    pub fn into_result(self) -> ToolResult {
        ToolResult::Error(self.to_string())
    }
}

impl From<serde_json::Error> for ToolError {
    fn from(e: serde_json::Error) -> Self {
        Self::ParseError(e.to_string())
    }
}

/// A completed tool call with its result, ready to be sent back to the AI.
#[derive(Debug, Clone)]
pub struct ToolCallResult {
    /// The original tool call.
    pub call: ToolCall,
    /// The execution result.
    pub result: ToolResult,
}

impl ToolCallResult {
    pub fn ok(call: ToolCall, value: serde_json::Value) -> Self {
        Self {
            call,
            result: ToolResult::Ok(value),
        }
    }

    pub fn error(call: ToolCall, message: impl Into<String>) -> Self {
        Self {
            call,
            result: ToolResult::Error(message.into()),
        }
    }

    pub fn from_result(call: ToolCall, result: ToolResult) -> Self {
        Self { call, result }
    }
}
