"""
ID Wispera LangChain Integration
Credential provider for LangChain applications
"""

from typing import Optional, Any
from pathlib import Path

try:
    from langchain_core.callbacks import CallbackManagerForLLMRun
    from langchain_core.language_models import BaseLLM
    LANGCHAIN_AVAILABLE = True
except ImportError:
    LANGCHAIN_AVAILABLE = False


class WisperaCredentialProvider:
    """
    Credential provider for LangChain that retrieves credentials from ID Wispera vault.

    Usage:
        from id_wispera.integrations.langchain import WisperaCredentialProvider
        from langchain_openai import ChatOpenAI

        provider = WisperaCredentialProvider(vault_path="~/.id-wispera")
        llm = ChatOpenAI(api_key=provider.get("openai-prod"))
    """

    def __init__(
        self,
        vault_path: Optional[str] = None,
        passphrase: Optional[str] = None,
        passphrase_env: str = "IDW_PASSPHRASE",
    ):
        """
        Initialize the credential provider.

        Args:
            vault_path: Path to the vault directory. Defaults to ~/.id-wispera
            passphrase: **Deprecated.** Do not pass a plaintext passphrase.
                Use ``idw auth login`` (OS keychain) or ``idw auth token create``
                (session token) instead.  This parameter will be removed in a
                future release.
            passphrase_env: Ignored when using PassphraseProvider. Retained
                for backward compatibility.
        """
        import os
        import warnings
        from id_wispera.auth import PassphraseProvider

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

        self._vault_path = Path(vault_path)
        self._vault: Optional["Vault"] = None
        self._cache: dict[str, str] = {}

        if passphrase is not None:
            warnings.warn(
                "Passing 'passphrase' directly is deprecated and will be removed "
                "in a future release. Use 'idw auth login' or session tokens instead.",
                DeprecationWarning,
                stacklevel=2,
            )
            self._passphrase: Optional[str] = passphrase
        else:
            provider = PassphraseProvider(
                allow_interactive=False,
                allow_env_var=True,
            )
            self._passphrase = provider.get_passphrase()

    def _ensure_vault(self) -> "Vault":
        """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(
        self,
        passport_name: str,
        *,
        platform: Optional[str] = None,
        log_access: bool = True,
    ) -> 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 the access (default: True)

        Returns:
            The credential value

        Raises:
            ValueError: If passport not found
        """
        # Check cache first
        cache_key = f"{passport_name}:{platform or ''}"
        if cache_key in self._cache:
            return self._cache[cache_key]

        vault = self._ensure_vault()

        # Find matching passport
        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}"
                    )

                # Log access
                if log_access:
                    from id_wispera.audit import log_action
                    from id_wispera.types import AuditAction

                    log_action(
                        vault,
                        passport_id=passport.id,
                        action=AuditAction.ACCESSED,
                        actor="langchain",
                        platform=platform or "langchain",
                        details="Credential accessed via LangChain provider",
                    )

                # Cache and return
                self._cache[cache_key] = passport.credential_value
                return passport.credential_value

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

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

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

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

    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()


# Convenience function for quick access
def get_credential(
    passport_name: str,
    vault_path: Optional[str] = None,
    platform: Optional[str] = None,
) -> str:
    """
    Quick access to a credential without creating a provider instance.

    Args:
        passport_name: Name of the passport
        vault_path: Optional vault path
        platform: Optional platform filter

    Returns:
        The credential value
    """
    provider = WisperaCredentialProvider(vault_path=vault_path)
    return provider.get(passport_name, platform=platform)
