//! `MetaCrate` grid-tool execution boundary and Mentra run limits.

use crate::llm::ToolDefinition;
use crate::types::{
    BoundedText, MAX_BODY_BYTES, MAX_CONVERSATION_MESSAGES, MAX_MESSAGE_BYTES, MAX_TOOL_CALLS,
    ProposedToolCall,
};
use libremetaverse_types::compat::CancellationToken;
use serde_json::Value;
use std::future::Future;
use std::pin::Pin;
use std::time::Duration;

const MAX_LOOP_TURNS: usize = 32;
const MAX_SESSION_TOOL_CALLS: usize = 256;

pub type ToolFuture<'a> = Pin<Box<dyn Future<Output = ToolExecution> + Send + 'a>>;

pub trait ToolExecutor: Send + Sync {
    fn execute<'a>(
        &'a self,
        definition: &'a ToolDefinition,
        call: &'a ProposedToolCall,
        arguments: &'a Value,
        cancellation: &'a CancellationToken,
    ) -> ToolFuture<'a>;
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ToolExecution {
    Completed(BoundedText<MAX_BODY_BYTES>),
    Rejected(BoundedText<MAX_MESSAGE_BYTES>),
    Failed(BoundedText<MAX_MESSAGE_BYTES>),
    AmbiguousMutation,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ToolLoopLimits {
    pub max_turns: usize,
    pub max_tool_calls_per_turn: usize,
    pub max_tool_calls_per_session: usize,
    pub max_history_messages: usize,
    pub max_history_bytes: usize,
    pub wall_clock_timeout: Duration,
}

impl Default for ToolLoopLimits {
    fn default() -> Self {
        Self {
            max_turns: 8,
            max_tool_calls_per_turn: 8,
            max_tool_calls_per_session: 32,
            max_history_messages: 64,
            max_history_bytes: 512 * 1024,
            wall_clock_timeout: Duration::from_mins(2),
        }
    }
}

impl ToolLoopLimits {
    /// # Errors
    ///
    /// Returns [`ToolLoopError::UnsafeLimits`] when any configured run bound
    /// is zero, internally inconsistent, or above its hard ceiling.
    pub fn validate(&self) -> Result<(), ToolLoopError> {
        if self.max_turns == 0
            || self.max_turns > MAX_LOOP_TURNS
            || self.max_tool_calls_per_turn == 0
            || self.max_tool_calls_per_turn > MAX_TOOL_CALLS
            || self.max_tool_calls_per_session == 0
            || self.max_tool_calls_per_session > MAX_SESSION_TOOL_CALLS
            || self.max_history_messages < 2
            || self.max_history_messages > MAX_CONVERSATION_MESSAGES
            || self.max_history_bytes < 1024
            || self.max_history_bytes > MAX_BODY_BYTES
            || self.wall_clock_timeout.is_zero()
            || self.wall_clock_timeout > Duration::from_mins(10)
        {
            return Err(ToolLoopError::UnsafeLimits);
        }
        Ok(())
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ToolLoopError {
    UnsafeLimits,
}
