#!/usr/bin/env python3
"""Single-user stdio MCP notes. Never expose this as a shared HTTP service."""
import argparse
import os
from pathlib import Path
import sqlite3
import tempfile
import uuid

DB = Path(os.environ.get("NOTES_DB", "data/notes.sqlite3"))


def connect():
    DB.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
    connection = sqlite3.connect(DB, timeout=5)
    connection.execute("CREATE TABLE IF NOT EXISTS notes (id TEXT PRIMARY KEY, title TEXT NOT NULL, body TEXT NOT NULL, created_at TEXT DEFAULT CURRENT_TIMESTAMP)")
    connection.row_factory = sqlite3.Row
    return connection


def add_note(title: str, body: str) -> dict:
    """Save a local note. Title is 1-240 characters; body is at most 20,000."""
    if not isinstance(title, str) or not 1 <= len(title.strip()) <= 240:
        raise ValueError("Title must contain 1-240 characters")
    if not isinstance(body, str) or len(body) > 20000:
        raise ValueError("Body must be a string of at most 20,000 characters")
    note_id = str(uuid.uuid4())
    connection = connect()
    try:
        with connection:
            connection.execute("INSERT INTO notes (id,title,body) VALUES (?,?,?)", (note_id, title.strip(), body))
    finally:
        connection.close()
    return {"id": note_id, "title": title.strip(), "body": body}


def list_notes(limit: int = 20) -> list[dict]:
    """List the latest local notes, with a bounded result count."""
    if type(limit) is not int or not 1 <= limit <= 50:
        raise ValueError("Limit must be an integer from 1 to 50")
    connection = connect()
    try:
        return [dict(row) for row in connection.execute("SELECT * FROM notes ORDER BY created_at DESC, rowid DESC LIMIT ?", (limit,))]
    finally:
        connection.close()


def delete_note(note_id: str) -> dict:
    """Permanently delete this local note. Obtain user confirmation first."""
    if not isinstance(note_id, str):
        raise ValueError("A UUID note ID is required")
    uuid.UUID(note_id)
    connection = connect()
    try:
        with connection:
            cursor = connection.execute("DELETE FROM notes WHERE id=?", (note_id,))
        return {"deleted": cursor.rowcount == 1}
    finally:
        connection.close()


def self_test():
    global DB
    original = DB
    try:
        with tempfile.TemporaryDirectory() as directory:
            DB = Path(directory) / "test.sqlite3"
            note = add_note(" FIELD GUIDE TEST ", "Only disposable data")
            assert list_notes()[0]["title"] == "FIELD GUIDE TEST"
            assert list_notes()[0]["id"] == note["id"]
            assert delete_note(note["id"]) == {"deleted": True}
            assert list_notes() == []
            assert delete_note(note["id"]) == {"deleted": False}
            for operation in [lambda: add_note(" ", "x"), lambda: add_note("x", "y" * 20001), lambda: list_notes(51), lambda: delete_note("invalid")]:
                try:
                    operation()
                except ValueError:
                    pass
                else:
                    raise AssertionError("Invalid input accepted")
    finally:
        DB = original
    print("Disposable SQLite create/list/delete and validation checks passed.")


if __name__ == "__main__":
    os.umask(0o077)
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--self-test", action="store_true")
    args = parser.parse_args()
    if args.self_test:
        self_test()
    else:
        from mcp.server.fastmcp import FastMCP
        server = FastMCP("field-notes")
        server.tool()(add_note)
        server.tool()(list_notes)
        server.tool()(delete_note)
        server.run(transport="stdio")
