"""Secure credential storage using OS system keyring."""

from __future__ import annotations

import json
import logging
from typing import Any

logger = logging.getLogger(__name__)

KEYRING_SERVICE_PREFIX = "mcp-eregistrations-bpa"


def _get_keyring() -> Any:
    """Lazy-import keyring to avoid hard dependency at module load."""
    try:
        import keyring
        import keyring.errors  # noqa: F401

        return keyring
    except ImportError:
        return None


def _service_name(instance_id: str) -> str:
    """Build keyring service name scoped to a BPA instance.

    Args:
        instance_id: Instance slug (e.g., "els-dev-a1b2c3").

    Returns:
        Keyring service name like "mcp-eregistrations-bpa/els-dev-a1b2c3".
    """
    return f"{KEYRING_SERVICE_PREFIX}/{instance_id}"


def store_credentials(instance_id: str, username: str, password: str) -> bool:
    """Store credentials in system keyring, scoped to instance.

    Args:
        instance_id: BPA instance slug.
        username: BPA username (email).
        password: BPA password.

    Returns:
        True if stored successfully, False if keyring unavailable.
    """
    kr = _get_keyring()
    if kr is None:
        logger.warning("keyring package not installed; credentials not stored")
        return False
    try:
        service = _service_name(instance_id)
        kr.set_password(service, "username", username)
        kr.set_password(service, "password", password)
        return True
    except Exception as e:
        # Clean up partial write (username stored but password failed)
        try:
            kr.delete_password(_service_name(instance_id), "username")
        except Exception:
            pass
        logger.warning("Cannot store credentials in keyring: %s", e)
        return False


def get_credentials(instance_id: str) -> tuple[str, str] | None:
    """Retrieve credentials from system keyring.

    Args:
        instance_id: BPA instance slug.

    Returns:
        (username, password) tuple, or None if not found or keyring unavailable.
    """
    kr = _get_keyring()
    if kr is None:
        return None
    try:
        service = _service_name(instance_id)
        username = kr.get_password(service, "username")
        password = kr.get_password(service, "password")
        if username and password:
            return (username, password)
        return None
    except Exception as e:
        logger.warning("Cannot read credentials from keyring: %s", e)
        return None


def delete_credentials(instance_id: str) -> None:
    """Remove stored credentials from keyring. Silently ignores missing entries.

    Args:
        instance_id: BPA instance slug.
    """
    kr = _get_keyring()
    if kr is None:
        return
    try:
        import keyring.errors

        service = _service_name(instance_id)
        try:
            kr.delete_password(service, "username")
        except keyring.errors.PasswordDeleteError:
            pass
        try:
            kr.delete_password(service, "password")
        except keyring.errors.PasswordDeleteError:
            pass
    except Exception as e:
        logger.warning("Cannot delete credentials from keyring: %s", e)


# ---------------------------------------------------------------------------
# CAS client secret storage
# ---------------------------------------------------------------------------

_CAS_SECRET_KEY = "cas_client_secret"


def store_cas_secret(instance_id: str, secret: str) -> bool:
    """Store CAS client secret in system keyring, scoped to instance.

    Args:
        instance_id: BPA instance slug.
        secret: CAS client secret value.

    Returns:
        True if stored successfully, False if keyring unavailable.
    """
    kr = _get_keyring()
    if kr is None:
        logger.warning("keyring package not installed; CAS secret not stored")
        return False
    try:
        kr.set_password(_service_name(instance_id), _CAS_SECRET_KEY, secret)
        return True
    except Exception as e:
        logger.warning("Cannot store CAS secret in keyring: %s", e)
        return False


def get_cas_secret(instance_id: str) -> str | None:
    """Retrieve CAS client secret from system keyring.

    Args:
        instance_id: BPA instance slug.

    Returns:
        Secret string, or None if not found or keyring unavailable.
    """
    kr = _get_keyring()
    if kr is None:
        return None
    try:
        secret: str | None = kr.get_password(
            _service_name(instance_id), _CAS_SECRET_KEY
        )
        return secret
    except Exception as e:
        logger.warning("Cannot read CAS secret from keyring: %s", e)
        return None


def delete_cas_secret(instance_id: str) -> None:
    """Remove stored CAS client secret from keyring. Silently ignores missing entries.

    Args:
        instance_id: BPA instance slug.
    """
    kr = _get_keyring()
    if kr is None:
        return
    try:
        import keyring.errors

        try:
            kr.delete_password(_service_name(instance_id), _CAS_SECRET_KEY)
        except keyring.errors.PasswordDeleteError:
            pass
    except Exception as e:
        logger.warning("Cannot delete CAS secret from keyring: %s", e)


# ---------------------------------------------------------------------------
# Refresh context storage (cross-session token refresh)
# ---------------------------------------------------------------------------

_REFRESH_CONTEXT_KEY = "refresh_context"


def store_refresh_context(instance_id: str, context: dict[str, str]) -> bool:
    """Store refresh context in system keyring for cross-session auth.

    Args:
        instance_id: BPA instance slug.
        context: Dict with refresh_token, token_endpoint, client_id.

    Returns:
        True if stored successfully, False if keyring unavailable.
    """
    kr = _get_keyring()
    if kr is None:
        logger.warning("keyring package not installed; refresh context not stored")
        return False
    try:
        payload = json.dumps(context)
        kr.set_password(_service_name(instance_id), _REFRESH_CONTEXT_KEY, payload)
        return True
    except Exception as e:
        logger.warning("Cannot store refresh context in keyring: %s", e)
        return False


def get_refresh_context(instance_id: str) -> dict[str, str] | None:
    """Retrieve refresh context from system keyring.

    Args:
        instance_id: BPA instance slug.

    Returns:
        Dict with refresh_token, token_endpoint, client_id, or None.
    """
    kr = _get_keyring()
    if kr is None:
        return None
    try:
        raw: str | None = kr.get_password(
            _service_name(instance_id), _REFRESH_CONTEXT_KEY
        )
        if raw:
            result: dict[str, str] = json.loads(raw)
            return result
        return None
    except Exception as e:
        logger.warning("Cannot read refresh context from keyring: %s", e)
        return None


def delete_refresh_context(instance_id: str) -> None:
    """Remove stored refresh context from keyring. Silently ignores missing entries.

    Args:
        instance_id: BPA instance slug.
    """
    kr = _get_keyring()
    if kr is None:
        return
    try:
        import keyring.errors

        try:
            kr.delete_password(_service_name(instance_id), _REFRESH_CONTEXT_KEY)
        except keyring.errors.PasswordDeleteError:
            pass
    except Exception as e:
        logger.warning("Cannot delete refresh context from keyring: %s", e)
