"""Server-level SQLite: user registry, refresh tokens, audit log."""
from __future__ import annotations
import sqlite3
import uuid
from pathlib import Path
from .base import User

_SCHEMA = """
CREATE TABLE IF NOT EXISTS auth (
    id            TEXT PRIMARY KEY,
    email         TEXT UNIQUE NOT NULL,
    password_hash TEXT,
    auth_provider TEXT NOT NULL DEFAULT 'local',
    active        INTEGER NOT NULL DEFAULT 1,
    created_at    TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS users (
    id         TEXT PRIMARY KEY REFERENCES auth(id),
    username   TEXT NOT NULL,
    role       TEXT NOT NULL DEFAULT 'pending',
    last_login TEXT,
    CONSTRAINT valid_role CHECK (role IN ('admin', 'user', 'pending', 'read-only'))
);
CREATE TABLE IF NOT EXISTS refresh_tokens (
    token_hash TEXT PRIMARY KEY,
    user_id    TEXT NOT NULL REFERENCES auth(id),
    expires_at TEXT NOT NULL,
    revoked    INTEGER NOT NULL DEFAULT 0,
    created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS audit_log (
    id        INTEGER PRIMARY KEY AUTOINCREMENT,
    timestamp TEXT NOT NULL DEFAULT (datetime('now')),
    user_id   TEXT,
    action    TEXT NOT NULL,
    detail    TEXT,
    ip_address TEXT
);
"""


_USER_COLS = "a.id, u.username, a.email, u.role, a.auth_provider"
_USER_JOIN = "FROM auth a JOIN users u ON a.id = u.id"
_VALID_ROLES = frozenset({"admin", "user", "pending", "read-only"})


def _connect(db_path: Path) -> sqlite3.Connection:
    """Open SQLite connection with foreign key enforcement."""
    conn = sqlite3.connect(db_path)
    conn.execute("PRAGMA foreign_keys = ON")
    return conn


def init_server_db(db_path: Path) -> None:
    conn = _connect(db_path)
    conn.executescript(_SCHEMA)
    conn.close()


def create_user(
    db_path: Path, *, username: str, email: str,
    password_hash: str | None, role: str = "user",
    auth_provider: str = "local",
) -> User:
    user_id = str(uuid.uuid4())
    conn = _connect(db_path)
    try:
        conn.execute(
            "INSERT INTO auth (id, email, password_hash, auth_provider) VALUES (?, ?, ?, ?)",
            (user_id, email, password_hash, auth_provider),
        )
        conn.execute(
            "INSERT INTO users (id, username, role) VALUES (?, ?, ?)",
            (user_id, username, role),
        )
        conn.commit()
    except sqlite3.IntegrityError as e:
        conn.close()
        err = str(e)
        if "valid_role" in err:
            raise ValueError(f"Invalid role: {role!r}. Must be one of: admin, user, pending, read-only") from e
        raise ValueError(f"Duplicate email: {email}") from e
    conn.close()
    return User(id=user_id, username=username, email=email, role=role, auth_provider=auth_provider)


def get_user_by_id(db_path: Path, user_id: str) -> User | None:
    conn = _connect(db_path)
    row = conn.execute(
        f"SELECT {_USER_COLS} {_USER_JOIN} WHERE a.id = ? AND a.active = 1",
        (user_id,),
    ).fetchone()
    conn.close()
    return User(*row) if row else None


def get_user_by_email(db_path: Path, email: str) -> User | None:
    conn = _connect(db_path)
    row = conn.execute(
        f"SELECT {_USER_COLS} {_USER_JOIN} WHERE a.email = ? AND a.active = 1",
        (email,),
    ).fetchone()
    conn.close()
    return User(*row) if row else None


def get_user_by_username(db_path: Path, username: str) -> User | None:
    conn = _connect(db_path)
    row = conn.execute(
        f"SELECT {_USER_COLS} {_USER_JOIN} WHERE u.username = ? AND a.active = 1",
        (username,),
    ).fetchone()
    conn.close()
    return User(*row) if row else None


def list_users(db_path: Path, role: str | None = None) -> list[User]:
    conn = _connect(db_path)
    if role:
        rows = conn.execute(
            f"SELECT {_USER_COLS} {_USER_JOIN} WHERE u.role = ? AND a.active = 1",
            (role,),
        ).fetchall()
    else:
        rows = conn.execute(
            f"SELECT {_USER_COLS} {_USER_JOIN} WHERE a.active = 1",
        ).fetchall()
    conn.close()
    return [User(*r) for r in rows]


def delete_user(db_path: Path, user_id: str) -> None:
    conn = _connect(db_path)
    with conn:
        conn.execute("DELETE FROM refresh_tokens WHERE user_id = ?", (user_id,))
        conn.execute("DELETE FROM users WHERE id = ?", (user_id,))
        conn.execute("DELETE FROM auth WHERE id = ?", (user_id,))
    conn.close()
