"""
ID Wispera Base Integration Provider
Common credential access logic shared by all framework integrations
"""

from typing import Optional, Any
from pathlib import Path


class WisperaBaseProvider:
    """
    Base credential provider that all framework integrations extend.
    Handles vault access, caching, audit logging, and credential lookup.

    Args:
        vault_path: Path to the vault directory. Defaults to ~/.id-wispera
        passphrase: Vault passphrase. If not provided, reads from environment.
        passphrase_env: Environment variable name for passphrase.
        actor: Actor name for audit logging.
        enable_cache: Whether to cache credentials in memory.
        log_access: Whether to log credential access to audit trail.
    """

    def __init__(
        self,
        vault_path: Optional[str] = None,
        passphrase: Optional[str] = None,
        passphrase_env: str = "IDW_PASSPHRASE",
        actor: str = "integration",
        enable_cache: bool = True,
        log_access: bool = True,
    ):
        import os

        if vault_path is None:
            vault_path = os.path.expanduser("~/.id-wispera")

        self._vault_path = Path(vault_path)
        self._passphrase = passphrase or os.environ.get(passphrase_env)
        self._vault = None
        self._actor = actor
        self._enable_cache = enable_cache
        self._log_access = log_access
        self._cache: dict[str, str] = {}

        if not self._passphrase:
            raise ValueError(
                f"Passphrase required. Set {passphrase_env} environment variable "
                "or pass passphrase parameter."
            )

    def _ensure_vault(self):
        """Ensure vault is loaded and unlocked."""
        if self._vault is None:
            from id_wispera.vault import Vault

            vault_file = self._vault_path / "vault.json"
            if not vault_file.exists():
                raise FileNotFoundError(
                    f"Vault not found at {vault_file}. Run 'idw-py init' first."
                )

            self._vault = Vault.load(vault_file, self._passphrase)

        return self._vault

    def _get_passport(self, passport_name: str, platform: Optional[str] = None):
        """Get a passport by name with optional platform filter."""
        vault = self._ensure_vault()
        passports = vault.list_passports()

        for passport in passports:
            if passport.name == passport_name:
                if platform and platform not in passport.platforms:
                    continue

                if passport.status not in ("active", "expiring"):
                    raise ValueError(
                        f"Passport '{passport_name}' is {passport.status}"
                    )

                return passport

        raise ValueError(f"Passport not found: {passport_name}")

    def _log_access(self, passport_id: str, platform: str, details: str) -> None:
        """Log credential access to audit trail."""
        if not self._log_access:
            return

        from id_wispera.audit import log_action
        from id_wispera.types import AuditAction

        vault = self._ensure_vault()
        log_action(
            vault,
            passport_id=passport_id,
            action=AuditAction.ACCESSED,
            actor=self._actor,
            platform=platform,
            details=details,
        )

    def get(
        self,
        passport_name: str,
        *,
        platform: Optional[str] = None,
        log_access: Optional[bool] = None,
        purpose: Optional[str] = None,
    ) -> str:
        """
        Get a credential value by passport name.

        Args:
            passport_name: Name of the passport to retrieve
            platform: Optional platform filter
            log_access: Whether to log access (overrides provider default)
            purpose: Purpose of access (recorded in audit log)

        Returns:
            The credential value
        """
        cache_key = f"{passport_name}:{platform or ''}"
        if self._enable_cache and cache_key in self._cache:
            return self._cache[cache_key]

        passport = self._get_passport(passport_name, platform)

        should_log = log_access if log_access is not None else self._log_access
        if should_log:
            self._log_access_entry(
                passport.id,
                platform or self._actor,
                purpose or f"Credential accessed via {self._actor} provider",
            )

        if self._enable_cache:
            self._cache[cache_key] = passport.credential_value

        return passport.credential_value

    def _log_access_entry(self, passport_id: str, platform: str, details: str) -> None:
        """Log credential access to audit trail (internal)."""
        from id_wispera.audit import log_action
        from id_wispera.types import AuditAction

        vault = self._ensure_vault()
        log_action(
            vault,
            passport_id=passport_id,
            action=AuditAction.ACCESSED,
            actor=self._actor,
            platform=platform,
            details=details,
        )

    def get_openai_key(self, passport_name: str = "openai") -> str:
        """Get OpenAI API key."""
        return self.get(passport_name, platform="openai")

    def get_anthropic_key(self, passport_name: str = "anthropic") -> str:
        """Get Anthropic API key."""
        return self.get(passport_name, platform="anthropic")

    def get_azure_key(self, passport_name: str = "azure") -> str:
        """Get Azure AI API key."""
        return self.get(passport_name, platform="azure-ai")

    def get_llm_config(
        self,
        passport_name: str,
        model: Optional[str] = None,
        **extra_config: Any,
    ) -> dict[str, Any]:
        """
        Get LLM configuration.

        Args:
            passport_name: Name of the passport containing the API key
            model: Optional model name
            **extra_config: Additional configuration

        Returns:
            LLM configuration dictionary
        """
        passport = self._get_passport(passport_name)
        provider = self._detect_provider(passport.platforms)

        config: dict[str, Any] = {
            "api_key": passport.credential_value,
            "provider": provider or "custom",
        }

        if model:
            config["model"] = model
        elif provider == "openai":
            config["model"] = "gpt-4"
        elif provider == "anthropic":
            config["model"] = "claude-sonnet-4-5-20250514"
        elif provider == "azure":
            config["model"] = "gpt-4"
        elif provider == "google":
            config["model"] = "gemini-pro"

        config.update(extra_config)
        return config

    def _detect_provider(self, platforms: list[str]) -> Optional[str]:
        """Detect LLM provider from platform list."""
        provider_map = {
            "openai": "openai",
            "anthropic": "anthropic",
            "azure-ai": "azure",
            "google-a2a": "google",
        }

        for platform in platforms:
            if platform in provider_map:
                return provider_map[platform]

        return None

    def list_available(self, platform: Optional[str] = None) -> list[str]:
        """
        List available passport names.

        Args:
            platform: Optional platform filter

        Returns:
            List of passport names
        """
        vault = self._ensure_vault()
        passports = vault.list_passports()

        names = []
        for passport in passports:
            if passport.status in ("active", "expiring"):
                if platform is None or platform in passport.platforms:
                    names.append(passport.name)

        return names

    def clear_cache(self) -> None:
        """Clear the credential cache."""
        self._cache.clear()
