"""Centralized provider API key resolution.

All provider key lookups in the codebase MUST go through this module.

Resolution order:
1. Environment variable (highest priority — backwards compat, power users)
2. ~/.robot-resources/config.json under provider_keys
3. None
"""

from __future__ import annotations

import json
import os
from pathlib import Path

import structlog

logger = structlog.get_logger()

_DEFAULT_CONFIG_PATH = Path.home() / ".robot-resources" / "config.json"

# Maps environment variable names to config.json provider_keys field names.
_ENV_TO_CONFIG: dict[str, str] = {
    "OPENAI_API_KEY": "openai",
    "ANTHROPIC_API_KEY": "anthropic",
    "GOOGLE_API_KEY": "google",
}


def _read_provider_keys_from_config(config_path: Path | None = None) -> dict[str, str]:
    """Read provider_keys from config.json.

    Returns a dict of ``{provider_name: api_key}`` with only non-empty
    string values.  Returns empty dict on any failure (file missing,
    malformed JSON, unexpected structure).
    """
    path = config_path or _DEFAULT_CONFIG_PATH
    try:
        raw = path.read_text(encoding="utf-8")
        config = json.loads(raw)
    except (FileNotFoundError, OSError):
        return {}
    except json.JSONDecodeError:
        logger.warning("keys_invalid_config_json", path=str(path))
        return {}

    keys = config.get("provider_keys", {})
    if not isinstance(keys, dict):
        return {}
    return {k: v for k, v in keys.items() if isinstance(v, str) and v}


def get_provider_key(
    env_var: str, *, config_path: Path | None = None
) -> str | None:
    """Get a provider API key by its environment variable name.

    Resolution order:
    1. ``os.environ[env_var]`` (if non-empty)
    2. ``config.json`` → ``provider_keys[<mapped_name>]``
    3. ``None``

    Args:
        env_var: Environment variable name (e.g. ``"OPENAI_API_KEY"``).
        config_path: Override config file path (for testing).

    Returns:
        The API key string, or None if not configured anywhere.
    """
    # Env var takes priority
    env_value = os.environ.get(env_var)
    if env_value:
        return env_value

    # Fall back to config.json
    config_key = _ENV_TO_CONFIG.get(env_var)
    if config_key is None:
        # Unknown env var — no config.json mapping exists
        return None

    config_keys = _read_provider_keys_from_config(config_path)
    return config_keys.get(config_key) or None


def get_available_provider_names(
    *, config_path: Path | None = None
) -> set[str]:
    """Get the set of provider names that have API keys configured.

    Checks both environment variables and config.json.
    Returns lowercase provider names (e.g. ``{"openai", "google"}``).
    """
    available: set[str] = set()
    config_keys = _read_provider_keys_from_config(config_path)

    for env_var, provider_name in _ENV_TO_CONFIG.items():
        env_value = os.environ.get(env_var)
        if env_value:
            available.add(provider_name)
        elif config_keys.get(provider_name):
            available.add(provider_name)

    return available
