"""Authentication and credential storage for Cerebro MCP Server.

Fallback chain:
1. Environment variables (CEREBRO_HOST, CEREBRO_USER, CEREBRO_PASSWORD)
2. Cerebro Desktop client (connect_from_cerebro_client)
3. Saved credentials (~/.cerebro-mcp/config.json + keyring)
4. No credentials — require login tool call
"""

import json
import os
import sys
from pathlib import Path

CONFIG_DIR = Path.home() / ".cerebro-mcp"
CONFIG_FILE = CONFIG_DIR / "config.json"
KEYRING_SERVICE = "cerebro-mcp"


def _load_config() -> dict:
    """Load saved config from ~/.cerebro-mcp/config.json."""
    if CONFIG_FILE.exists():
        try:
            return json.loads(CONFIG_FILE.read_text())
        except (json.JSONDecodeError, OSError):
            pass
    return {}


def _save_config(host: str, username: str, password: str | None = None):
    """Save credentials. Password goes to keyring if available, else to config file."""
    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    config = {"host": host, "username": username}

    saved_to_keyring = False
    if password:
        try:
            import keyring
            keyring.set_password(KEYRING_SERVICE, username, password)
            saved_to_keyring = True
        except Exception:
            config["password"] = password
            print(
                "WARNING: keyring недоступен, пароль сохранён в config.json. "
                "Установите keyring для безопасного хранения: pip install keyring",
                file=sys.stderr,
            )

    CONFIG_FILE.write_text(json.dumps(config, indent=2))
    return saved_to_keyring


def _get_password(username: str) -> str | None:
    """Get password from keyring or config file."""
    try:
        import keyring
        pw = keyring.get_password(KEYRING_SERVICE, username)
        if pw:
            return pw
    except Exception:
        pass

    config = _load_config()
    return config.get("password")


def connect_db():
    """Try to connect to Cerebro using the fallback chain.

    Returns:
        (database.Database, str) — connected db instance and method description
    Raises:
        ConnectionError — if no method succeeds and no credentials available
    """
    from cerebro_mcp._vendor.pycerebro import database

    # 1. Environment variables
    env_host = os.environ.get("CEREBRO_HOST", "")
    env_user = os.environ.get("CEREBRO_USER")
    env_pass = os.environ.get("CEREBRO_PASSWORD")

    if env_user and env_pass:
        db = database.Database()
        db.connect(env_user, env_pass, primary_url=env_host)
        return db, f"env vars (user={env_user})"

    # 2. Cerebro Desktop client
    try:
        db = database.Database()
        status = db.connect_from_cerebro_client()
        if status == 0:
            return db, "Cerebro Desktop client"
    except Exception:
        pass

    # 3. Saved credentials
    config = _load_config()
    if config.get("username"):
        password = _get_password(config["username"])
        if password:
            db = database.Database()
            db.connect(config["username"], password, primary_url=config.get("host", ""))
            return db, f"saved credentials (user={config['username']})"

    # 4. No credentials
    raise ConnectionError(
        "Не удалось подключиться к Cerebro. Способы:\n"
        "1. Запустите Cerebro Desktop и залогиньтесь\n"
        "2. Вызовите инструмент login(host, username, password)\n"
        "3. Установите переменные CEREBRO_HOST, CEREBRO_USER, CEREBRO_PASSWORD"
    )


def login(host: str, username: str, password: str):
    """Login with explicit credentials. Save for future use.

    Returns:
        database.Database — connected instance
    """
    from cerebro_mcp._vendor.pycerebro import database

    db = database.Database()
    db.connect(username, password, primary_url=host)
    _save_config(host, username, password)
    return db
