// Enhanced MCP Tools for Systems Provisioning
// Integrates with new API server, AI agents, and dashboard capabilities

use std::process::Command;

use anyhow::Result;
use reqwest::Client;
use serde_json::{json, Value};

pub struct ProvisioningTools {
    client: Client,
    api_base_url: String,
    api_port: u16,
    dashboard_port: u16,
}

impl ProvisioningTools {
    pub fn new(api_base_url: Option<String>) -> Self {
        Self::with_ports(api_base_url, None, None)
    }

    pub fn with_ports(
        api_base_url: Option<String>,
        api_port: Option<u16>,
        dashboard_port: Option<u16>,
    ) -> Self {
        let api_port = api_port.unwrap_or(3000);
        let dashboard_port = dashboard_port.unwrap_or(8080);
        Self {
            client: Client::new(),
            api_base_url: api_base_url.unwrap_or_else(|| format!("http://localhost:{}", api_port)),
            api_port,
            dashboard_port,
        }
    }

    /// Execute provisioning command with enhanced capabilities
    pub async fn execute_provisioning_command(&self, args: &[&str]) -> Result<Value> {
        let output = Command::new("./core/nulib/provisioning")
            .args(args)
            .output()
            .map_err(|e| anyhow::anyhow!("Failed to execute command: {}", e))?;

        let stdout = String::from_utf8_lossy(&output.stdout);
        let stderr = String::from_utf8_lossy(&output.stderr);

        if output.status.success() {
            Ok(json!({
                "success": true,
                "stdout": stdout,
                "stderr": stderr,
                "exit_code": 0
            }))
        } else {
            Ok(json!({
                "success": false,
                "stdout": stdout,
                "stderr": stderr,
                "exit_code": output.status.code().unwrap_or(-1)
            }))
        }
    }

    /// Query infrastructure using AI-powered natural language
    pub async fn ai_query(&self, query: &str, context: Option<&str>) -> Result<Value> {
        let mut args = vec!["ai", "query", "--prompt", query];

        if let Some(ctx) = context {
            args.extend(&["--context", ctx]);
        }

        let output = Command::new("./core/nulib/provisioning")
            .args(&args)
            .output()
            .map_err(|e| anyhow::anyhow!(format!("AI query failed: {}", e)))?;

        let result = String::from_utf8_lossy(&output.stdout);

        // Try to parse as JSON, fallback to plain text
        if let Ok(parsed) = serde_json::from_str::<Value>(&result) {
            Ok(parsed)
        } else {
            Ok(json!({
                "query": query,
                "response": result.trim(),
                "type": "natural_language_response"
            }))
        }
    }

    /// Get infrastructure status via API
    pub async fn get_infrastructure_status(&self) -> Result<Value> {
        let url = format!("{}/api/v1/query?target=infrastructure", self.api_base_url);

        match self.client.get(&url).send().await {
            Ok(response) => {
                if response.status().is_success() {
                    let data = response
                        .json::<Value>()
                        .await
                        .map_err(|e| anyhow::anyhow!(format!("Failed to parse response: {}", e)))?;
                    Ok(data)
                } else {
                    // Fallback to CLI command
                    self.execute_provisioning_command(&["show", "infrastructure"])
                        .await
                }
            }
            Err(_) => {
                // Fallback to CLI command
                self.execute_provisioning_command(&["show", "infrastructure"])
                    .await
            }
        }
    }

    /// Get system metrics via API
    pub async fn get_system_metrics(&self, timerange: Option<&str>) -> Result<Value> {
        let timerange = timerange.unwrap_or("1h");
        let url = format!(
            "{}/api/v1/metrics?timerange={}",
            self.api_base_url, timerange
        );

        match self.client.get(&url).send().await {
            Ok(response) => {
                if response.status().is_success() {
                    let data = response
                        .json::<Value>()
                        .await
                        .map_err(|e| anyhow::anyhow!(format!("Failed to parse metrics: {}", e)))?;
                    Ok(data)
                } else {
                    // Fallback to CLI command
                    self.execute_provisioning_command(&["query", "metrics", "--since", timerange])
                        .await
                }
            }
            Err(_) => {
                // Fallback to CLI command
                self.execute_provisioning_command(&["query", "metrics", "--since", timerange])
                    .await
            }
        }
    }

    /// Get logs with filtering via API
    pub async fn get_logs(&self, level: Option<&str>, since: Option<&str>) -> Result<Value> {
        let level = level.unwrap_or("info");
        let since = since.unwrap_or("1h");
        let url = format!(
            "{}/api/v1/logs?level={}&since={}",
            self.api_base_url, level, since
        );

        match self.client.get(&url).send().await {
            Ok(response) => {
                if response.status().is_success() {
                    let data = response
                        .json::<Value>()
                        .await
                        .map_err(|e| anyhow::anyhow!(format!("Failed to parse logs: {}", e)))?;
                    Ok(data)
                } else {
                    // Fallback to CLI command
                    self.execute_provisioning_command(&["logs", "--level", level, "--since", since])
                        .await
                }
            }
            Err(_) => {
                // Fallback to CLI command
                self.execute_provisioning_command(&["logs", "--level", level, "--since", since])
                    .await
            }
        }
    }

    /// Start API server
    pub async fn start_api_server(&self, port: Option<u16>) -> Result<Value> {
        let port = port.unwrap_or(self.api_port);
        let port_str = port.to_string();

        self.execute_provisioning_command(&["api", "start", "--port", &port_str, "--background"])
            .await
    }

    /// Get API server status
    pub async fn get_api_status(&self) -> Result<Value> {
        let url = format!("{}/health", self.api_base_url);

        match self.client.get(&url).send().await {
            Ok(response) => {
                let status = response.status();
                let data = response
                    .json::<Value>()
                    .await
                    .unwrap_or(json!({"status": "unknown"}));

                Ok(json!({
                    "api_available": status.is_success(),
                    "status_code": status.as_u16(),
                    "data": data
                }))
            }
            Err(e) => Ok(json!({
                "api_available": false,
                "error": e.to_string()
            })),
        }
    }

    /// Create and start dashboard
    pub async fn create_dashboard(
        &self,
        template: Option<&str>,
        name: Option<&str>,
    ) -> Result<Value> {
        let template = template.unwrap_or("full");
        let name = name.unwrap_or("ai-dashboard");

        self.execute_provisioning_command(&["dashboard", "create", template, name])
            .await
    }

    /// Start existing dashboard
    pub async fn start_dashboard(&self, name: &str, port: Option<u16>) -> Result<Value> {
        let port = port.unwrap_or(self.dashboard_port);
        let port_str = port.to_string();

        self.execute_provisioning_command(&["dashboard", "start", name, &port_str])
            .await
    }

    /// Start AI agents
    pub async fn start_ai_agents(&self, agents: Option<Vec<&str>>) -> Result<Value> {
        let mut args = vec!["agents", "start"];
        let agents_str;

        if let Some(agent_list) = agents {
            args.push("--agents");
            agents_str = format!("[{}]", agent_list.join(", "));
            args.push(&agents_str);
        }

        self.execute_provisioning_command(&args).await
    }

    /// Get AI agents status
    pub async fn get_agents_status(&self) -> Result<Value> {
        self.execute_provisioning_command(&["agents", "status"])
            .await
    }

    /// Create servers with configuration
    pub async fn create_servers(&self, config: &Value) -> Result<Value> {
        let template = config
            .get("template")
            .and_then(|v| v.as_str())
            .unwrap_or("default");
        let count = config.get("count").and_then(|v| v.as_u64()).unwrap_or(1);
        let provider = config
            .get("provider")
            .and_then(|v| v.as_str())
            .unwrap_or("local");
        let instance_type = config.get("instance_type").and_then(|v| v.as_str());

        let count_str = count.to_string();
        let mut args = vec![
            "server",
            "create",
            "--template",
            template,
            "--count",
            &count_str,
            "--provider",
            provider,
        ];

        if let Some(itype) = instance_type {
            args.extend(&["--instance-type", itype]);
        }

        self.execute_provisioning_command(&args).await
    }

    /// List servers
    pub async fn list_servers(&self, provider: Option<&str>) -> Result<Value> {
        let mut args = vec!["server", "list"];

        if let Some(p) = provider {
            args.extend(&["--provider", p]);
        }

        self.execute_provisioning_command(&args).await
    }

    /// Delete servers
    pub async fn delete_servers(&self, server_names: &[&str]) -> Result<Value> {
        let mut args = vec!["server", "delete"];
        args.extend(server_names);

        self.execute_provisioning_command(&args).await
    }

    /// Create Kubernetes cluster
    pub async fn create_cluster(&self, config: &Value) -> Result<Value> {
        let name = config
            .get("name")
            .and_then(|v| v.as_str())
            .unwrap_or("k8s-cluster");
        let nodes = config.get("nodes").and_then(|v| v.as_u64()).unwrap_or(3);
        let provider = config
            .get("provider")
            .and_then(|v| v.as_str())
            .unwrap_or("local");

        let nodes_str = nodes.to_string();
        let args = vec![
            "cluster",
            "create",
            "--name",
            name,
            "--nodes",
            &nodes_str,
            "--provider",
            provider,
        ];

        self.execute_provisioning_command(&args).await
    }

    /// Generate infrastructure from natural language description
    pub async fn generate_infrastructure(
        &self,
        description: &str,
        output_type: Option<&str>,
    ) -> Result<Value> {
        let output_type = output_type.unwrap_or("server");

        let args = vec![
            "ai",
            "template",
            "--prompt",
            description,
            "--template-type",
            output_type,
        ];

        self.execute_provisioning_command(&args).await
    }

    /// Get cost optimization recommendations
    pub async fn get_cost_optimization(&self) -> Result<Value> {
        self.ai_query(
            "How can I reduce infrastructure costs and optimize spending?",
            None,
        )
        .await
    }

    /// Get security analysis
    pub async fn get_security_analysis(&self) -> Result<Value> {
        self.ai_query(
            "Perform a security analysis of current infrastructure and identify threats",
            None,
        )
        .await
    }

    /// Get performance analysis
    pub async fn get_performance_analysis(&self) -> Result<Value> {
        self.ai_query("Analyze system performance and identify bottlenecks", None)
            .await
    }

    /// Predict infrastructure issues
    pub async fn predict_issues(&self, timeframe: Option<&str>) -> Result<Value> {
        let timeframe = timeframe.unwrap_or("next week");
        let query = format!("Predict potential infrastructure issues for {}", timeframe);

        self.ai_query(&query, None).await
    }
}
