"""
Credential management for g-gremlin CLI.

Provides secure storage and retrieval of secrets via:
- Environment variables (CI mode)
- OS keychain (macOS Keychain Access, Windows Credential Manager)
- Legacy plaintext files (backward compatibility, read-only)
- External secret manager plugins (M2)
"""

from __future__ import annotations

import json
import warnings
from pathlib import Path
from typing import Callable, Dict, Iterable

from g_gremlin.credentials.models import (
    IntegrationSpec,
    IntegrationStatus,
    SecretSource,
    SecretValue,
    INTEGRATION_REGISTRY,
)
from g_gremlin.credentials.provider import (
    CredentialBackend,
    CredentialProvider,
    CredentialProviderError,
    SecretNotFoundError,
    BackendUnavailableError,
)
from g_gremlin.paths import gremlin_path


def _unified_credentials_path() -> Path:
    override = globals().get("UNIFIED_CREDENTIALS_PATH")
    if isinstance(override, Path):
        return override
    if isinstance(override, str) and override.strip():
        return Path(override)
    return gremlin_path("credentials.json")


def __getattr__(name: str) -> Path:
    if name == "UNIFIED_CREDENTIALS_PATH":
        return _unified_credentials_path()
    raise AttributeError(f"module {__name__!r} has no attribute {name!r}")


def resolve_credentials(
    service: str,
    required_keys: Iterable[str],
    optional_keys: Iterable[str] | None = None,
    credential_provider: CredentialProvider | None = None,
    legacy_loader: Callable[[], Dict[str, str]] | None = None,
) -> Dict[str, str]:
    """
    Resolve credentials for a service using multiple fallback sources.

    Order:
    1. CredentialProvider (env/keychain/legacy backends)
    2. Unified ~/.g_gremlin/credentials.json
    3. Optional legacy loader callback
    """
    provider = credential_provider or CredentialProvider()
    resolved: Dict[str, str] = {}
    missing: list[str] = []

    for key in required_keys:
        try:
            secret = provider.get_secret(service, key)
            resolved[key] = secret.value
        except SecretNotFoundError:
            missing.append(key)

    if missing:
        unified = _load_unified_credentials(service)
        for key in list(missing):
            if unified.get(key):
                resolved[key] = unified[key]
                missing.remove(key)

    if missing and legacy_loader:
        legacy = legacy_loader()
        for key in list(missing):
            if legacy.get(key):
                resolved[key] = legacy[key]
                missing.remove(key)
        if legacy:
            warnings.warn(
                f"{service} credentials loaded from legacy config; migrate to CredentialProvider.",
                DeprecationWarning,
                stacklevel=2,
            )

    if missing:
        raise SecretNotFoundError(f"Missing credentials for {service}: {', '.join(missing)}")

    if optional_keys:
        unified = _load_unified_credentials(service)
        for key in optional_keys:
            try:
                secret = provider.get_secret(service, key)
                resolved[key] = secret.value
            except SecretNotFoundError:
                if unified.get(key):
                    resolved[key] = unified[key]

    return resolved


def _load_unified_credentials(service: str) -> Dict[str, str]:
    """Load credentials from unified credentials file."""
    unified_credentials_path = _unified_credentials_path()
    if not unified_credentials_path.exists():
        return {}
    try:
        data = json.loads(unified_credentials_path.read_text(encoding="utf-8"))
        service_data = data.get(service) or {}
        if service_data:
            warnings.warn(
                f"Using credentials from {unified_credentials_path}. Prefer CredentialProvider or env vars.",
                DeprecationWarning,
                stacklevel=3,
            )
        return {k: str(v) for k, v in service_data.items()}
    except Exception:
        return {}


__all__ = [
    # Models
    "SecretValue",
    "SecretSource",
    "IntegrationStatus",
    "IntegrationSpec",
    "INTEGRATION_REGISTRY",
    # Provider
    "CredentialProvider",
    "CredentialBackend",
    "CredentialProviderError",
    "SecretNotFoundError",
    "BackendUnavailableError",
    # Helpers
    "resolve_credentials",
    "UNIFIED_CREDENTIALS_PATH",
]
