//! Miscellaneous tools: take_screenshot, code_coverage, code_search.

use anyhow::Result;
use tracing::debug;

use crate::ui_writer::UiWriter;
use crate::ToolCall;

use super::executor::ToolContext;

/// Execute the `take_screenshot` tool.
pub async fn execute_take_screenshot<W: UiWriter>(
    tool_call: &ToolCall,
    ctx: &ToolContext<'_, W>,
) -> Result<String> {
    debug!("Processing take_screenshot tool call");
    
    let controller = match ctx.computer_controller {
        Some(c) => c,
        None => {
            return Ok(
                "❌ Computer control not enabled. Set computer_control.enabled = true in config."
                    .to_string(),
            )
        }
    };

    let path = tool_call
        .args
        .get("path")
        .and_then(|v| v.as_str())
        .ok_or_else(|| anyhow::anyhow!("Missing path argument"))?;

    // Extract window_id (app name) - REQUIRED
    let window_id = tool_call
        .args
        .get("window_id")
        .and_then(|v| v.as_str())
        .ok_or_else(|| {
            anyhow::anyhow!(
                "Missing window_id argument. You must specify which window to capture \
                (e.g., 'Safari', 'Terminal', 'Google Chrome')."
            )
        })?;

    // Extract region if provided
    let region = tool_call
        .args
        .get("region")
        .and_then(|v| v.as_object())
        .map(|region_obj| g3_computer_control::types::Rect {
            x: region_obj.get("x").and_then(|v| v.as_i64()).unwrap_or(0) as i32,
            y: region_obj.get("y").and_then(|v| v.as_i64()).unwrap_or(0) as i32,
            width: region_obj
                .get("width")
                .and_then(|v| v.as_i64())
                .unwrap_or(0) as i32,
            height: region_obj
                .get("height")
                .and_then(|v| v.as_i64())
                .unwrap_or(0) as i32,
        });

    match controller.take_screenshot(path, region, Some(window_id)).await {
        Ok(_) => {
            // Get the actual path where the screenshot was saved
            let actual_path = if path.starts_with('/') {
                path.to_string()
            } else {
                let temp_dir = std::env::var("TMPDIR")
                    .or_else(|_| std::env::var("HOME").map(|h| format!("{}/tmp", h)))
                    .unwrap_or_else(|_| "/tmp".to_string());
                format!("{}/{}", temp_dir.trim_end_matches('/'), path)
            };

            Ok(format!(
                "✅ Screenshot of {} saved to: {}",
                window_id, actual_path
            ))
        }
        Err(e) => Ok(format!("❌ Failed to take screenshot: {}", e)),
    }
}

/// Execute the `code_coverage` tool.
pub async fn execute_code_coverage<W: UiWriter>(
    tool_call: &ToolCall,
    ctx: &ToolContext<'_, W>,
) -> Result<String> {
    debug!("Processing code_coverage tool call");
    let _ = tool_call; // unused
    
    ctx.ui_writer
        .print_context_status("🔍 Generating code coverage report...");

    // Ensure coverage tools are installed
    match g3_execution::ensure_coverage_tools_installed() {
        Ok(already_installed) => {
            if !already_installed {
                ctx.ui_writer
                    .print_context_status("✅ Coverage tools installed successfully");
            }
        }
        Err(e) => {
            return Ok(format!("❌ Failed to install coverage tools: {}", e));
        }
    }

    // Run cargo llvm-cov --workspace
    let output = std::process::Command::new("cargo")
        .args(["llvm-cov", "--workspace"])
        .current_dir(std::env::current_dir()?)
        .output()?;

    if output.status.success() {
        let stdout = String::from_utf8_lossy(&output.stdout);
        let stderr = String::from_utf8_lossy(&output.stderr);

        let mut result = String::from("✅ Code coverage report generated successfully\n\n");
        result.push_str("## Coverage Summary\n");
        result.push_str(&stdout);
        if !stderr.is_empty() {
            result.push_str("\n## Warnings\n");
            result.push_str(&stderr);
        }
        Ok(result)
    } else {
        let stderr = String::from_utf8_lossy(&output.stderr);
        Ok(format!("❌ Failed to generate coverage report:\n{}", stderr))
    }
}

/// Execute the `code_search` tool.
pub async fn execute_code_search<W: UiWriter>(
    tool_call: &ToolCall,
    _ctx: &ToolContext<'_, W>,
) -> Result<String> {
    debug!("Processing code_search tool call");

    // Parse the request
    let request: crate::code_search::CodeSearchRequest =
        match serde_json::from_value(tool_call.args.clone()) {
            Ok(req) => req,
            Err(e) => {
                return Ok(format!("❌ Invalid code_search arguments: {}", e));
            }
        };

    // Execute the code search
    match crate::code_search::execute_code_search(request).await {
        Ok(response) => {
            // Serialize the response to JSON
            match serde_json::to_string_pretty(&response) {
                Ok(json_output) => Ok(format!("✅ Code search completed\n{}", json_output)),
                Err(e) => Ok(format!("❌ Failed to serialize response: {}", e)),
            }
        }
        Err(e) => Ok(format!("❌ Code search failed: {}", e)),
    }
}
