use agent_types::common::ids::{ToolId, ToolName};
use agent_types::tool::spec_types::{EffectProfile, InputSchemaRef, OutputContract};

use super::constants::{default_timeout_ms, max_timeout_ms};
use agent_contracts::tool::ToolSpecView;

#[derive(Debug, Clone)]
pub struct BashToolSpec {
    id: ToolId,
    name: ToolName,
    description: String,
    input_schema: InputSchemaRef,
    output_contract: OutputContract,
    effect_profile: EffectProfile,
}

impl BashToolSpec {
    pub fn new() -> Self {
        let schema = serde_json::json!({
            "type": "object",
            "properties": {
                "command": {
                    "type": "string",
                    "description": "The bash command to execute"
                },
                "cwd": {
                    "type": "string",
                    "description": "Optional working directory for the command"
                },
                "timeout": {
                    "type": "number",
                    "description": format!(
                        "Optional timeout in milliseconds. Defaults to {}ms and may not exceed {}ms",
                        default_timeout_ms(),
                        max_timeout_ms()
                    )
                }
            },
            "required": ["command"]
        });

        Self {
            id: ToolId("builtin_bash".to_string()),
            name: ToolName("bash".to_string()),
            description: "Executes a bash command and returns structured process output"
                .to_string(),
            input_schema: InputSchemaRef { schema },
            output_contract: OutputContract {
                description:
                    "Output from bash including stdout/stderr, truncation flags, exit_code, and interruption state"
                        .to_string(),
            },
            effect_profile: EffectProfile {
                reads_filesystem: true,
                writes_filesystem: true,
                network_access: false,
                side_effects: true,
            },
        }
    }
}

impl Default for BashToolSpec {
    fn default() -> Self {
        Self::new()
    }
}

impl ToolSpecView for BashToolSpec {
    fn id(&self) -> &ToolId {
        &self.id
    }

    fn name(&self) -> &ToolName {
        &self.name
    }

    fn description(&self) -> &str {
        &self.description
    }

    fn input_schema(&self) -> &InputSchemaRef {
        &self.input_schema
    }

    fn output_contract(&self) -> &OutputContract {
        &self.output_contract
    }

    fn effect_profile(&self) -> &EffectProfile {
        &self.effect_profile
    }
}