"""中控 SQLite。"""

from __future__ import annotations

from pathlib import Path
from threading import Lock
from typing import Any

from .config import get_control_settings

_SCHEMA = """
CREATE TABLE IF NOT EXISTS nodes (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL,
  base_url TEXT NOT NULL UNIQUE,
  token_sealed TEXT NOT NULL DEFAULT '',
  created_at_ms INTEGER NOT NULL,
  updated_at_ms INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS meta (
  key TEXT PRIMARY KEY,
  value TEXT NOT NULL
);
"""

_db: "ControlDB | None" = None
_lock = Lock()


def set_control_db(db: "ControlDB | None") -> None:
    global _db
    _db = db


def get_control_db() -> "ControlDB":
    if _db is None:
        raise RuntimeError("control db not initialized")
    return _db


class ControlDB:
    def __init__(self, path: Path | None = None) -> None:
        import sqlite3
        import time

        settings = get_control_settings()
        self.path = path or settings.db_path
        self.path.parent.mkdir(parents=True, exist_ok=True)
        self._conn = sqlite3.connect(str(self.path), check_same_thread=False)
        self._conn.row_factory = sqlite3.Row
        self._conn.executescript(_SCHEMA)
        self._conn.commit()
        self._lock = Lock()
        # touch
        _ = time.time()

    def close(self) -> None:
        self._conn.close()

    def list_nodes(self) -> list[dict[str, Any]]:
        with self._lock:
            rows = self._conn.execute(
                "SELECT id, name, base_url, token_sealed, created_at_ms, updated_at_ms FROM nodes ORDER BY id"
            ).fetchall()
        return [dict(r) for r in rows]

    def get_node(self, node_id: int) -> dict[str, Any] | None:
        with self._lock:
            row = self._conn.execute(
                "SELECT id, name, base_url, token_sealed, created_at_ms, updated_at_ms FROM nodes WHERE id=?",
                (node_id,),
            ).fetchone()
        return dict(row) if row else None

    def create_node(self, name: str, base_url: str) -> dict[str, Any]:
        import time

        now = int(time.time() * 1000)
        name = name.strip()
        base_url = base_url.strip().rstrip("/")
        with self._lock:
            cur = self._conn.execute(
                "INSERT INTO nodes(name, base_url, token_sealed, created_at_ms, updated_at_ms) VALUES (?,?,?,?,?)",
                (name, base_url, "", now, now),
            )
            self._conn.commit()
            nid = int(cur.lastrowid)
        return self.get_node(nid)  # type: ignore[return-value]

    def update_node(
        self,
        node_id: int,
        *,
        name: str | None = None,
        base_url: str | None = None,
        token_sealed: str | None = None,
    ) -> dict[str, Any] | None:
        import time

        node = self.get_node(node_id)
        if not node:
            return None
        now = int(time.time() * 1000)
        new_name = name.strip() if name is not None else node["name"]
        new_url = base_url.strip().rstrip("/") if base_url is not None else node["base_url"]
        new_tok = token_sealed if token_sealed is not None else node["token_sealed"]
        with self._lock:
            self._conn.execute(
                "UPDATE nodes SET name=?, base_url=?, token_sealed=?, updated_at_ms=? WHERE id=?",
                (new_name, new_url, new_tok, now, node_id),
            )
            self._conn.commit()
        return self.get_node(node_id)

    def delete_node(self, node_id: int) -> bool:
        with self._lock:
            cur = self._conn.execute("DELETE FROM nodes WHERE id=?", (node_id,))
            self._conn.commit()
            return cur.rowcount > 0
