"""Azure Key Vault secret client."""

from typing import Optional
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient as AzureSecretClient

from .cache import SecretCache
from .exceptions import SecretNotFoundError, AuthenticationError, AzureVaultException


class SecretClient:
    """Client for accessing secrets from Azure Key Vault.
    
    This client provides methods to retrieve secrets from Azure Key Vault
    with optional caching to reduce API calls.
    """

    def __init__(
        self,
        vault_url: str,
        cache_ttl_seconds: int = 300,
        enable_cache: bool = True,
    ):
        """Initialize the Secret Client.
        
        Args:
            vault_url: The URL of the Azure Key Vault (e.g., https://<vault-name>.vault.azure.net/).
            cache_ttl_seconds: Cache TTL in seconds. Defaults to 300 (5 minutes).
            enable_cache: Whether to enable caching. Defaults to True.
            
        Raises:
            AuthenticationError: If authentication with Azure fails.
            AzureVaultException: If the vault URL is invalid.
        """
        if not vault_url:
            raise AzureVaultException("vault_url cannot be empty")

        self.vault_url = vault_url
        self.enable_cache = enable_cache
        self.cache = SecretCache(ttl_seconds=cache_ttl_seconds) if enable_cache else None

        try:
            credential = DefaultAzureCredential()
            self._client = AzureSecretClient(vault_url=vault_url, credential=credential)
        except Exception as e:
            raise AuthenticationError(f"Failed to authenticate with Azure Key Vault: {str(e)}")

    def get_secret(self, secret_name: str) -> str:
        """Retrieve a secret from Azure Key Vault.
        
        Args:
            secret_name: The name of the secret to retrieve.
            
        Returns:
            The secret value.
            
        Raises:
            SecretNotFoundError: If the secret is not found in the vault.
            AzureVaultException: If an error occurs while retrieving the secret.
        """
        # Check cache first if enabled
        if self.enable_cache and self.cache:
            cached_value = self.cache.get(secret_name)
            if cached_value is not None:
                return cached_value

        try:
            secret = self._client.get_secret(secret_name)
            value = secret.value

            # Cache the secret if caching is enabled
            if self.enable_cache and self.cache:
                self.cache.set(secret_name, value)

            return value
        except Exception as e:
            if "SecretNotFound" in str(e.__class__.__name__):
                raise SecretNotFoundError(f"Secret '{secret_name}' not found in vault")
            raise AzureVaultException(f"Failed to retrieve secret '{secret_name}': {str(e)}")

    def set_secret(self, secret_name: str, secret_value: str) -> None:
        """Store a secret in Azure Key Vault.
        
        Args:
            secret_name: The name of the secret.
            secret_value: The value of the secret.
            
        Raises:
            AzureVaultException: If an error occurs while storing the secret.
        """
        try:
            self._client.set_secret(secret_name, secret_value)
            # Invalidate cache for this secret
            if self.enable_cache and self.cache:
                self.cache.remove(secret_name)
        except Exception as e:
            raise AzureVaultException(f"Failed to set secret '{secret_name}': {str(e)}")

    def delete_secret(self, secret_name: str) -> None:
        """Delete a secret from Azure Key Vault.
        
        Args:
            secret_name: The name of the secret to delete.
            
        Raises:
            AzureVaultException: If an error occurs while deleting the secret.
        """
        try:
            self._client.begin_delete_secret(secret_name)
            # Remove from cache if present
            if self.enable_cache and self.cache:
                self.cache.remove(secret_name)
        except Exception as e:
            raise AzureVaultException(f"Failed to delete secret '{secret_name}': {str(e)}")

    def list_secrets(self) -> list:
        """List all secrets in the Azure Key Vault.
        
        Returns:
            A list of secret names.
            
        Raises:
            AzureVaultException: If an error occurs while listing secrets.
        """
        try:
            secrets = self._client.list_properties_of_secrets()
            return [secret.name for secret in secrets]
        except Exception as e:
            raise AzureVaultException(f"Failed to list secrets: {str(e)}")

    def clear_cache(self) -> None:
        """Clear the secret cache."""
        if self.enable_cache and self.cache:
            self.cache.clear()

    def close(self) -> None:
        """Close the client connection."""
        if hasattr(self._client, "close"):
            self._client.close()
