import os
import logging
from dataclasses import dataclass, field
from pathlib import Path

from google.auth.transport.requests import Request
from google.oauth2 import service_account
from google.auth import exceptions as google_auth_exceptions

logger = logging.getLogger(__name__)

# User-provided service account key path (optional, for GCP Cloud Run auth)
# Set GOOGLE_APPLICATION_CREDENTIALS env var to provide your own key
_CREDENTIALS_PATH = Path(__file__).parent.parent / "credentials" / "service-account.json"

# Default Cloud Run URL
_DEFAULT_PROXY_URL = "http://34.111.149.123"

# Guest API key used when no PULI_API_KEY / PROXY_API_KEY is set.
# Grants GUEST-level access (BYO LLM key required).
_GUEST_API_KEY = "puli-proxy-api-key"


def _load_credentials(target_audience: str) -> service_account.IDTokenCredentials | None:
    """Load GCP credentials from the bundled service account key."""
    sa_path = os.environ.get("GOOGLE_APPLICATION_CREDENTIALS", str(_CREDENTIALS_PATH))

    if not Path(sa_path).exists():
        return None

    return service_account.IDTokenCredentials.from_service_account_file(
        sa_path, target_audience=target_audience
    )


@dataclass
class ProxyConfig:
    """Configuration for the proxy client."""

    base_url: str
    api_key: str
    _credentials: service_account.IDTokenCredentials | None = field(
        default=None, repr=False
    )
    _jwt_token: str | None = field(default=None, repr=False)

    @property
    def identity_token(self) -> str | None:
        """Get a valid identity token, refreshing automatically if expired."""
        if self._credentials is None:
            return None

        if not self._credentials.valid:
            try:
                self._credentials.refresh(Request())
            except google_auth_exceptions.RefreshError as e:
                logger.warning(
                    "Failed to refresh GCP identity token: %s. "
                    "Continuing without GCP auth (may fail if proxy requires it).",
                    e
                )
                self._credentials = None
                return None

        return self._credentials.token

    @property
    def jwt_token(self) -> str | None:
        return self._jwt_token

    @jwt_token.setter
    def jwt_token(self, value: str | None) -> None:
        self._jwt_token = value

    @classmethod
    def from_env(cls) -> "ProxyConfig":
        """Load configuration from environment variables."""
        base_url = os.environ.get("PROXY_BASE_URL", _DEFAULT_PROXY_URL)
        if not base_url:
            raise ValueError("PROXY_BASE_URL environment variable is required")

        # PULI_API_KEY takes priority over PROXY_API_KEY (legacy).
        # If neither is set, fall back to the guest API key (GUEST role).
        api_key = os.environ.get("PULI_API_KEY") or os.environ.get("PROXY_API_KEY")
        if not api_key:
            logger.info(
                "No PULI_API_KEY set — defaulting to guest access. "
                "Set PULI_API_KEY to use a personal or team API key."
            )
            api_key = _GUEST_API_KEY

        credentials = _load_credentials(target_audience=base_url)

        return cls(
            base_url=base_url.rstrip("/"),
            api_key=api_key,
            _credentials=credentials,
        )
