//! Cached MCP tool + prompt schema lists.
//!
//! Wrapped in `OnceLock` so the JSON values are constructed once
//! per process even though `tools/list` and `prompts/list` get
//! called frequently. The schemas are static — adding a new tool
//! means editing this file.

use serde_json::{json, Value};
use std::sync::OnceLock;

pub fn cached_tool_schemas() -> &'static Vec<Value> {
    static SCHEMAS: OnceLock<Vec<Value>> = OnceLock::new();
    SCHEMAS.get_or_init(tool_schemas)
}

pub fn cached_prompt_schemas() -> &'static Vec<Value> {
    static PROMPTS: OnceLock<Vec<Value>> = OnceLock::new();
    PROMPTS.get_or_init(prompt_schemas)
}

fn tool_schemas() -> Vec<Value> {
    vec![
        json!({
            "name": "memory_add_fact",
            "description": "Ingest a fact into CAR's graph memory. Kind defaults to \"pattern\"; use \"constraint\" for hard rules.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "subject": { "type": "string" },
                    "body": { "type": "string" },
                    "kind": { "type": "string", "enum": ["pattern", "constraint"] },
                },
                "required": ["subject", "body"],
            },
        }),
        json!({
            "name": "memory_query",
            "description": "Query CAR graph memory using spreading activation. Returns top-k nodes with activation scores.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "query": { "type": "string" },
                    "k": { "type": "integer", "minimum": 1, "maximum": 50 },
                },
                "required": ["query"],
            },
        }),
        json!({
            "name": "verify",
            "description": "Statically verify an ActionProposal: detect dependency cycles, missing tools, and simulate final state. No execution, no side effects.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "proposal": { "type": "object", "description": "A car_ir::ActionProposal JSON object" },
                    "max_actions": { "type": "integer", "minimum": 1, "maximum": 1000 },
                },
                "required": ["proposal"],
            },
        }),
        json!({
            "name": "skill_ingest",
            "description": "Ingest a skill into CAR's graph memory. A skill is executable code associated with a trigger (persona + url pattern + task keywords) so skill_find can later retrieve it for matching tasks.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "name": { "type": "string" },
                    "code": { "type": "string", "description": "Skill body — code, recipe, or procedure text" },
                    "platform": { "type": "string" },
                    "persona": { "type": "string" },
                    "url_pattern": { "type": "string" },
                    "description": { "type": "string" },
                    "task_keywords": { "type": "array", "items": { "type": "string" } },
                    "supersedes": { "type": "string", "description": "Name of an older skill this replaces" },
                },
                "required": ["name", "code"],
            },
        }),
        json!({
            "name": "skill_list",
            "description": "Enumerate all ingested skills. Optional domain filter returns only skills scoped Global or Domain(domain).",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "domain": { "type": "string" },
                },
            },
        }),
        json!({
            "name": "skill_find",
            "description": "Find top-k skills matching a persona/url/task triple, ranked by activation.",
            "inputSchema": {
                "type": "object",
                "properties": {
                    "persona": { "type": "string" },
                    "url": { "type": "string" },
                    "task": { "type": "string" },
                    "k": { "type": "integer", "minimum": 1, "maximum": 20 },
                },
                "required": ["task"],
            },
        }),
    ]
}

fn prompt_schemas() -> Vec<Value> {
    vec![json!({
        "name": "car_context",
        "description": "Assemble CAR's four-layer context (identity → constraints → facts → conversation → environment → known-unknowns) for a query. Returns the context as a single user message the host can prepend to its own prompt.",
        "arguments": [
            { "name": "query", "description": "Task or question the context should be assembled for.", "required": true },
            { "name": "mode", "description": "\"full\" (default) or \"fast\" — fast skips embedding flush, skill lookup, PPR scoring.", "required": false },
        ],
    })]
}
