//! Stdio entry point for lumotia-mcp. Reads newline-delimited JSON-RPC messages
//! from stdin, dispatches via `lumotia_mcp::handle_message`, writes responses to
//! stdout. Logs land on stderr so they don't collide with the JSON-RPC stream.

use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};

#[tokio::main(flavor = "current_thread")]
async fn main() -> anyhow::Result<()> {
    let db_path = lumotia_storage::database_path();
    eprintln!(
        "[lumotia-mcp] opening Lumotia database at {} (read-only)",
        db_path.display()
    );
    // Open read-only at the connection level so the MCP server cannot write
    // to the user's database, regardless of which tools the dispatcher
    // exposes. Migrations are deliberately skipped — this binary never owns
    // the schema; the main app is the single migration writer.
    let pool = lumotia_storage::init_readonly(&db_path).await?;
    eprintln!("[lumotia-mcp] ready, waiting for JSON-RPC on stdin");

    let mut lines = BufReader::new(tokio::io::stdin()).lines();
    let mut stdout = tokio::io::stdout();

    while let Some(line) = lines.next_line().await? {
        let trimmed = line.trim();
        if trimmed.is_empty() {
            continue;
        }

        let response = match serde_json::from_str::<serde_json::Value>(trimmed) {
            Ok(raw) => match lumotia_mcp::handle_message(&pool, raw).await {
                Some(response) => response,
                None => continue, // notification — no reply
            },
            Err(err) => {
                // Per JSON-RPC 2.0 §5.1: a Parse Error responds with
                // code -32700 and id null. Previously this branch
                // logged and continued, dropping the response —
                // clients saw silence instead of a structured error
                // (2026-04-22 review MAJOR).
                eprintln!("[lumotia-mcp] parse error: {err}");
                lumotia_mcp::parse_error_response(&err.to_string())
            }
        };

        let payload = serde_json::to_string(&response)?;
        stdout.write_all(payload.as_bytes()).await?;
        stdout.write_all(b"\n").await?;
        stdout.flush().await?;
    }

    Ok(())
}
