//! Minimaler MCP-stdio-Server (`app --mcp-panel`), den claude als Tool-Server
//! startet. Er stellt genau ein Tool bereit: `write_panel(text)` schreibt den
//! Text in die Panel-Datei aus `AI_CONTROL_PANEL` (dieselbe Env, die der
//! Terminal-Prozess der PTY mitgibt und die claude an seine MCP-Kinder vererbt).
//! Der bestehende Datei-Watcher im Terminal-Prozess zieht den Inhalt ins Panel.
//!
//! Protokoll: JSON-RPC 2.0, newline-getrennt (ein Objekt pro Zeile).

use serde_json::{json, Value};
use std::io::{BufRead, Write};

pub fn run_mcp_panel() {
  let stdin = std::io::stdin();
  let mut stdout = std::io::stdout();
  let mut reader = stdin.lock();
  let mut line = String::new();

  loop {
    line.clear();
    if reader.read_line(&mut line).unwrap_or(0) == 0 {
      break; // stdin geschlossen -> claude hat den Server beendet
    }
    let trimmed = line.trim();
    if trimmed.is_empty() {
      continue;
    }
    let Ok(req) = serde_json::from_str::<Value>(trimmed) else {
      continue;
    };

    let id = req.get("id").cloned();
    let method = req.get("method").and_then(Value::as_str).unwrap_or("");
    let result = handle(method, &req);

    // Nur Requests (mit id) bekommen eine Antwort; Notifications nicht.
    let (Some(id), Some(result)) = (id, result) else {
      continue;
    };
    let resp = json!({ "jsonrpc": "2.0", "id": id, "result": result });
    if writeln!(stdout, "{resp}").is_err() || stdout.flush().is_err() {
      break;
    }
  }
}

/// Liefert das `result` für einen Request, oder None für Notifications/Unbekanntes.
fn handle(method: &str, req: &Value) -> Option<Value> {
  match method {
    "initialize" => {
      // Vom Client vorgeschlagene Protokollversion übernehmen.
      let protocol = req["params"]["protocolVersion"]
        .as_str()
        .unwrap_or("2024-11-05");
      Some(json!({
        "protocolVersion": protocol,
        "capabilities": { "tools": {} },
        "serverInfo": { "name": "text-panel", "version": env!("CARGO_PKG_VERSION") },
      }))
    }
    "tools/list" => Some(json!({
      "tools": [
        {
          "name": "write_panel",
          "description":
            "Legt einen längeren Entwurf (ADR, E-Mail, Dokument, Spezifikation, \
             Commit-Message, Textbaustein) im ai-control-Panel neben dem Terminal \
             ab, wo er mit der Maus selektierbar und über einen Button kopierbar \
             ist. Statt den Text zusätzlich als Fließtext auszugeben, dieses Tool \
             aufrufen und im Chat nur kurz bestätigen.",
          "inputSchema": {
            "type": "object",
            "properties": {
              "text": {
                "type": "string",
                "description": "Vollständiger Entwurf als Markdown-Rohtext.",
              }
            },
            "required": ["text"],
          },
        },
        {
          "name": "archive_panel",
          "description":
            "Archiviert den aktuell im Panel liegenden Entwurf dauerhaft als \
             Markdown-Datei im Archiv-Ordner des Projekts. Auf Wunsch nutzen \
             (Nutzer sagt etwa „archiviere das“). Ist kein Ordner konfiguriert, \
             den Zielpfad im \
             Argument `dir` mitgeben (der Nutzer nennt ihn); ohne `dir` und ohne \
             konfigurierten Ordner meldet das Tool das zurück.",
          "inputSchema": {
            "type": "object",
            "properties": {
              "dir": {
                "type": "string",
                "description":
                  "Optionaler Archiv-Ordner. Wird gesetzt und für künftige \
                   Archivierungen gemerkt.",
              }
            },
          },
        },
      ],
    })),
    "tools/call" => Some(call_tool(req)),
    "ping" => Some(json!({})),
    _ => None,
  }
}

fn call_tool(req: &Value) -> Value {
  match req["params"]["name"].as_str().unwrap_or("") {
    "write_panel" => call_write(req),
    "archive_panel" => call_archive(req),
    other => json!({
      "content": [{ "type": "text", "text": format!("Unbekanntes Tool: {other}") }],
      "isError": true,
    }),
  }
}

fn call_write(req: &Value) -> Value {
  let text = req["params"]["arguments"]["text"].as_str().unwrap_or("");
  match std::env::var("AI_CONTROL_PANEL") {
    Ok(path) => match std::fs::write(&path, text) {
      Ok(()) => json!({ "content": [{ "type": "text", "text": "Entwurf ins Panel geschrieben." }] }),
      Err(e) => json!({
        "content": [{ "type": "text", "text": format!("Panel-Datei nicht schreibbar: {e}") }],
        "isError": true,
      }),
    },
    Err(_) => json!({
      "content": [{ "type": "text", "text": "AI_CONTROL_PANEL nicht gesetzt (Terminal außerhalb ai-control)." }],
      "isError": true,
    }),
  }
}

fn call_archive(req: &Value) -> Value {
  let project = std::env::var("AI_CONTROL_PROJECT").unwrap_or_default();
  let dir = req["params"]["arguments"]["dir"].as_str();
  match crate::archive_panel_content(&project, dir) {
    Ok(path) => json!({
      "content": [{ "type": "text", "text": format!("Archiviert: {}", path.display()) }],
    }),
    Err(e) => json!({
      "content": [{
        "type": "text",
        "text": format!("Nicht archiviert: {e}. Zielordner im Argument `dir` angeben oder im Panel wählen."),
      }],
      "isError": true,
    }),
  }
}
