//! MCP tool definitions -- maps CLI commands to tool descriptors.

use serde::Serialize;
use serde_json::{json, Value};

/// A single MCP tool descriptor.
#[derive(Debug, Clone, Serialize)]
pub struct ToolDefinition {
    /// Unique tool name (e.g. `"fxt_service_list"`).
    pub name: String,
    /// Human-readable description of what the tool does.
    pub description: String,
    /// JSON Schema for the tool's input arguments.
    #[serde(rename = "inputSchema")]
    pub input_schema: Value,
}

/// Returns all available tool definitions.
///
/// Organised by domain: services, training, trading, models,
/// broker, risk, data, cluster, agent, config, tune.
pub fn all_tools() -> Vec<ToolDefinition> {
    vec![
        // ── Service operations ──────────────────────────────────────
        tool(
            "fxt_service_list",
            "List all services with health status",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_service_status",
            "Get detailed status of a specific service",
            json!({
                "type": "object",
                "properties": {
                    "service": {"type": "string", "description": "Service name"}
                },
                "required": ["service"]
            }),
        ),
        tool(
            "fxt_service_health",
            "Health check all services",
            json!({"type": "object", "properties": {}}),
        ),
        // ── Training ────────────────────────────────────────────────
        tool(
            "fxt_train_start",
            "Start ML training job",
            json!({
                "type": "object",
                "properties": {
                    "model": {
                        "type": "string",
                        "description": "Model type (dqn, ppo, tft, mamba2, tggn, tlob, liquid, kan, xlstm, diffusion)"
                    },
                    "symbol": {
                        "type": "string",
                        "description": "Trading symbol (e.g. ES.FUT)"
                    }
                },
                "required": ["model"]
            }),
        ),
        tool(
            "fxt_train_stop",
            "Stop a training job",
            json!({
                "type": "object",
                "properties": {
                    "job_id": {"type": "string", "description": "Training job identifier"}
                },
                "required": ["job_id"]
            }),
        ),
        tool(
            "fxt_train_status",
            "Get training job status and metrics",
            json!({
                "type": "object",
                "properties": {
                    "job_id": {"type": "string", "description": "Training job identifier (omit for latest)"}
                }
            }),
        ),
        tool(
            "fxt_train_list",
            "List all training jobs",
            json!({"type": "object", "properties": {}}),
        ),
        // ── Trading ─────────────────────────────────────────────────
        tool(
            "fxt_trade_positions",
            "Get current positions",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_trade_orders",
            "List active orders",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_trade_account",
            "Get account state (balance, margin, P&L)",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_trade_submit",
            "Place an order",
            json!({
                "type": "object",
                "properties": {
                    "symbol": {"type": "string", "description": "Trading symbol (e.g. ES.FUT)"},
                    "side": {"type": "string", "enum": ["buy", "sell"], "description": "Order side"},
                    "quantity": {"type": "number", "description": "Order quantity"},
                    "order_type": {"type": "string", "enum": ["market", "limit"], "description": "Order type"},
                    "price": {"type": "number", "description": "Limit price (required for limit orders)"}
                },
                "required": ["symbol", "side", "quantity", "order_type"]
            }),
        ),
        // ── Model management ────────────────────────────────────────
        tool(
            "fxt_model_list",
            "List available models",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_model_status",
            "Get model health and performance metrics",
            json!({
                "type": "object",
                "properties": {
                    "model": {"type": "string", "description": "Model name or identifier"}
                },
                "required": ["model"]
            }),
        ),
        tool(
            "fxt_model_predict",
            "Get model prediction for a symbol",
            json!({
                "type": "object",
                "properties": {
                    "model": {"type": "string", "description": "Model name"},
                    "symbol": {"type": "string", "description": "Trading symbol"}
                },
                "required": ["model", "symbol"]
            }),
        ),
        tool(
            "fxt_model_ensemble",
            "Get ensemble vote (aggregated prediction from all models)",
            json!({
                "type": "object",
                "properties": {
                    "symbol": {"type": "string", "description": "Trading symbol"}
                },
                "required": ["symbol"]
            }),
        ),
        // ── Broker ──────────────────────────────────────────────────
        tool(
            "fxt_broker_status",
            "Broker session status (FIX, heartbeat RTT)",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_broker_connect",
            "Establish broker session",
            json!({"type": "object", "properties": {}}),
        ),
        // ── Risk ────────────────────────────────────────────────────
        tool(
            "fxt_risk_status",
            "Risk system state (kill switches, circuit breakers)",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_risk_limits",
            "Current risk limits",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_risk_drawdown",
            "Drawdown statistics",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_risk_emergency",
            "Emergency controls (halt all trading or resume)",
            json!({
                "type": "object",
                "properties": {
                    "action": {
                        "type": "string",
                        "enum": ["halt", "resume"],
                        "description": "Emergency action"
                    }
                },
                "required": ["action"]
            }),
        ),
        // ── Data ────────────────────────────────────────────────────
        tool(
            "fxt_data_status",
            "Data feed status and freshness",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_data_feeds",
            "Active feed list",
            json!({"type": "object", "properties": {}}),
        ),
        // ── Cluster ─────────────────────────────────────────────────
        tool(
            "fxt_cluster_status",
            "Node/pod status",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_cluster_resources",
            "CPU/RAM/GPU utilization",
            json!({"type": "object", "properties": {}}),
        ),
        // ── Agent ───────────────────────────────────────────────────
        tool(
            "fxt_agent_start",
            "Start trading agent",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_agent_stop",
            "Stop trading agent",
            json!({"type": "object", "properties": {}}),
        ),
        tool(
            "fxt_agent_status",
            "Trading agent state",
            json!({"type": "object", "properties": {}}),
        ),
        // ── Config ──────────────────────────────────────────────────
        tool(
            "fxt_config_get",
            "Get configuration value",
            json!({
                "type": "object",
                "properties": {
                    "key": {"type": "string", "description": "Configuration key"}
                },
                "required": ["key"]
            }),
        ),
        tool(
            "fxt_config_set",
            "Set configuration value",
            json!({
                "type": "object",
                "properties": {
                    "key": {"type": "string", "description": "Configuration key"},
                    "value": {"type": "string", "description": "New value"}
                },
                "required": ["key", "value"]
            }),
        ),
        // ── Tune ────────────────────────────────────────────────────
        tool(
            "fxt_tune_start",
            "Start hyperparameter tuning (PSO/Argmin)",
            json!({
                "type": "object",
                "properties": {
                    "model": {
                        "type": "string",
                        "description": "Model type to tune"
                    }
                },
                "required": ["model"]
            }),
        ),
        tool(
            "fxt_tune_status",
            "Tuning progress and best parameters so far",
            json!({"type": "object", "properties": {}}),
        ),
    ]
}

/// Helper to build a [`ToolDefinition`].
fn tool(name: &str, description: &str, input_schema: Value) -> ToolDefinition {
    ToolDefinition {
        name: name.to_owned(),
        description: description.to_owned(),
        input_schema,
    }
}

#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
    use super::*;

    #[test]
    fn all_tools_non_empty() {
        let tools = all_tools();
        assert!(!tools.is_empty());
    }

    #[test]
    fn all_tool_names_unique() {
        let tools = all_tools();
        let mut names: Vec<&str> = tools.iter().map(|t| t.name.as_str()).collect();
        let count = names.len();
        names.sort_unstable();
        names.dedup();
        assert_eq!(names.len(), count, "duplicate tool names found");
    }

    #[test]
    fn tool_names_follow_convention() {
        let tools = all_tools();
        for t in &tools {
            assert!(
                t.name.starts_with("fxt_"),
                "tool name '{}' must start with 'fxt_'",
                t.name
            );
        }
    }

    #[test]
    fn tool_schemas_are_objects() {
        let tools = all_tools();
        for t in &tools {
            let ty = t.input_schema.get("type");
            assert_eq!(
                ty,
                Some(&json!("object")),
                "tool '{}' input_schema.type must be 'object'",
                t.name
            );
        }
    }

    #[test]
    fn tool_definitions_serialize() {
        let tools = all_tools();
        let first = tools.first().unwrap();
        let json_str = serde_json::to_string(first).unwrap();
        assert!(json_str.contains("inputSchema"));
        assert!(json_str.contains(&first.name));
    }

    #[test]
    fn expected_tool_count() {
        // 3 service + 4 training + 4 trading + 4 model + 2 broker
        // + 4 risk + 2 data + 2 cluster + 3 agent + 2 config + 2 tune = 32
        let tools = all_tools();
        assert_eq!(tools.len(), 32);
    }
}
