"""API key management for the plyra-trace collector."""

import hashlib
import logging
import os
import secrets
import sqlite3
from datetime import UTC, datetime
from pathlib import Path
from typing import Any

logger = logging.getLogger("plyra_trace.collector.auth")

_KEYS_DB_PATH = "~/.plyra/keys.db"

_KEYS_SCHEMA = """
CREATE TABLE IF NOT EXISTS api_keys (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    key_prefix TEXT NOT NULL,
    key_hash TEXT NOT NULL UNIQUE,
    project_id TEXT NOT NULL,
    created_at TEXT NOT NULL,
    last_used_at TEXT,
    revoked INTEGER DEFAULT 0
);
"""


def _open_keys_db() -> sqlite3.Connection:
    expanded = os.path.expanduser(_KEYS_DB_PATH)
    Path(expanded).parent.mkdir(parents=True, exist_ok=True)
    conn = sqlite3.connect(expanded)
    conn.row_factory = sqlite3.Row
    conn.execute("PRAGMA journal_mode=WAL")
    conn.executescript(_KEYS_SCHEMA)
    conn.commit()
    return conn


def _hash_key(key: str) -> str:
    return hashlib.sha256(key.encode()).hexdigest()


def create_api_key(project: str, env: str = "live") -> str:
    """
    Generate a new API key for a project.

    Args:
        project: Project name the key is associated with
        env: 'live' or 'test'

    Returns:
        The full API key (shown only once — store it now!)

    Example:
        >>> key = create_api_key("opspilot")
        >>> print(key)
        plt_live_7f3a2bc849d1e6f0a3b5c8d2e4f1a9b7
    """
    random_part = secrets.token_hex(16)  # 32 hex chars
    key = f"plt_{env}_{random_part}"
    prefix = key[:14]  # e.g. "plt_live_7f3a"
    key_hash = _hash_key(key)
    now = datetime.now(UTC).isoformat()

    db = _open_keys_db()
    try:
        db.execute(
            "INSERT INTO api_keys (key_prefix, key_hash, project_id, created_at) VALUES (?, ?, ?, ?)",
            (prefix, key_hash, project, now),
        )
        db.commit()
    finally:
        db.close()

    return key


def list_api_keys() -> list[dict[str, Any]]:
    """
    List all API keys (prefixes only — hashes not exposed).

    Returns:
        List of key metadata dicts
    """
    db = _open_keys_db()
    try:
        rows = db.execute(
            "SELECT id, key_prefix, project_id, created_at, last_used_at, revoked"
            " FROM api_keys ORDER BY created_at DESC"
        ).fetchall()
        return [dict(r) for r in rows]
    finally:
        db.close()


def revoke_api_key(key_prefix: str) -> bool:
    """
    Revoke a key by prefix.

    Args:
        key_prefix: The prefix shown in `plyra-trace keys list`

    Returns:
        True if a key was found and revoked, False if not found
    """
    db = _open_keys_db()
    try:
        cur = db.execute(
            "UPDATE api_keys SET revoked = 1 WHERE key_prefix = ?",
            (key_prefix,),
        )
        db.commit()
        return cur.rowcount > 0
    finally:
        db.close()


def validate_api_key(key: str) -> bool:
    """
    Validate a full API key by comparing its SHA-256 hash.

    Args:
        key: Full API key from Authorization header

    Returns:
        True if valid and not revoked
    """
    key_hash = _hash_key(key)
    db = _open_keys_db()
    try:
        row = db.execute(
            "SELECT id FROM api_keys WHERE key_hash = ? AND revoked = 0",
            (key_hash,),
        ).fetchone()
        if row:
            # Update last_used_at
            db.execute(
                "UPDATE api_keys SET last_used_at = ? WHERE key_hash = ?",
                (datetime.now(UTC).isoformat(), key_hash),
            )
            db.commit()
            return True
        return False
    finally:
        db.close()


def handle_keys_command(args: Any) -> None:
    """
    Handle CLI `plyra-trace keys *` commands.

    Args:
        args: Parsed argparse namespace with keys_command attribute
    """
    command = getattr(args, "keys_command", None)

    if command == "create":
        key = create_api_key(args.project)
        print(f"\n  ◈ New API key created for project: {args.project}")
        print(f"\n  {key}")
        print("\n  ⚠ Save this key — it will NOT be shown again.")
        print(f"  Key prefix (for list/revoke): {key[:14]}\n")

    elif command == "list":
        keys = list_api_keys()
        if not keys:
            print("\n  No API keys found. Create one with: plyra-trace keys create --project NAME\n")
            return
        print(f"\n  {'PREFIX':<16} {'PROJECT':<20} {'CREATED':<26} {'LAST USED':<26} {'STATUS'}")
        print("  " + "─" * 90)
        for k in keys:
            status = "REVOKED" if k["revoked"] else "active"
            last_used = k["last_used_at"] or "never"
            print(f"  {k['key_prefix']:<16} {k['project_id']:<20} {k['created_at']:<26} {last_used:<26} {status}")
        print()

    elif command == "revoke":
        ok = revoke_api_key(args.key_prefix)
        if ok:
            print(f"\n  ✓ Key with prefix '{args.key_prefix}' has been revoked.\n")
        else:
            print(f"\n  ✗ No key found with prefix '{args.key_prefix}'.\n")

    else:
        print("\n  Usage: plyra-trace keys [create|list|revoke]\n")
