"""Notes API - minimal CRUD routing class with DbRoutingClass.

A pure routing class that knows nothing about ASGI, servers, or OpenAPI.
It just defines routes and uses self.db for database access.

When mounted via OpenApiApplication, it gets OpenAPI schema and
Swagger UI for free.
"""

import sqlite3
import uuid
from pathlib import Path

from genro_routes import DbRoutingClass, Router, route


class NotesAPI(DbRoutingClass):
    """Simple notes CRUD API."""

    openapi_info = {
        "title": "Notes API",
        "version": "1.0.0",
        "description": "Create, read, update and delete notes",
    }

    def __init__(self, db_uri: str = "sqlite:notes.db", **kwargs):
        self.api = Router(self, name="api")
        self._init_db(db_uri)

    def _init_db(self, db_uri: str) -> None:
        """Initialize SQLite database and create table if needed."""
        db_path = db_uri.replace("sqlite:", "")
        if not Path(db_path).is_absolute():
            db_path = str(Path(__file__).parent / db_path)
        self._conn = sqlite3.connect(db_path)
        self._conn.row_factory = sqlite3.Row
        self._conn.execute("""
            CREATE TABLE IF NOT EXISTS notes (
                id TEXT PRIMARY KEY,
                title TEXT NOT NULL,
                body TEXT DEFAULT '',
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
            )
        """)
        self._conn.commit()

    @route("api", openapi_method="get")
    def list(self, limit: int = 50) -> dict:
        """List all notes."""
        cursor = self._conn.execute(
            "SELECT id, title, body, created_at FROM notes ORDER BY created_at DESC LIMIT ?",
            (limit,),
        )
        rows = [dict(r) for r in cursor.fetchall()]
        return {"data": rows, "count": len(rows)}

    @route("api", openapi_method="get")
    def get(self, id: str) -> dict:
        """Get a single note by id."""
        cursor = self._conn.execute(
            "SELECT id, title, body, created_at FROM notes WHERE id = ?",
            (id,),
        )
        row = cursor.fetchone()
        if row is None:
            return {"error": "not found"}
        return {"data": dict(row)}

    @route("api", openapi_method="post")
    def add(self, title: str, body: str = "") -> dict:
        """Create a new note."""
        note_id = str(uuid.uuid4())[:8]
        self._conn.execute(
            "INSERT INTO notes (id, title, body) VALUES (?, ?, ?)",
            (note_id, title, body),
        )
        self._conn.commit()
        return {"data": {"id": note_id, "title": title, "body": body}}

    @route("api", openapi_method="post")
    def update(self, id: str, title: str = "", body: str = "") -> dict:
        """Update an existing note."""
        parts = []
        params = []
        if title:
            parts.append("title = ?")
            params.append(title)
        if body:
            parts.append("body = ?")
            params.append(body)
        if not parts:
            return {"error": "nothing to update"}
        params.append(id)
        self._conn.execute(
            f"UPDATE notes SET {', '.join(parts)} WHERE id = ?",
            params,
        )
        self._conn.commit()
        return self.get(id=id)

    @route("api", openapi_method="post")
    def delete(self, id: str) -> dict:
        """Delete a note."""
        self._conn.execute("DELETE FROM notes WHERE id = ?", (id,))
        self._conn.commit()
        return {"data": {"deleted": id}}


if __name__ == "__main__":
    pass
