"""Secret resolver for ${secret:NAME} references in environment variables."""

from __future__ import annotations

import re
from collections.abc import Callable

# Pattern for ${secret:NAME} syntax
# NAME must start with letter or underscore, followed by alphanumeric or underscore
SECRET_PATTERN = re.compile(r"\$\{secret:([A-Za-z_][A-Za-z0-9_]*)\}")


class SecretResolver:
    """Resolves ${secret:NAME} references in environment variables.

    By default, uses the global SecretStore to look up secrets.
    A custom getter function can be provided for testing or alternative
    secret sources.
    """

    def __init__(self, secret_getter: Callable[[str], str] | None = None) -> None:
        """Initialize the resolver.

        Args:
            secret_getter: Function that takes a secret name and returns its value.
                          If None, uses the global SecretStore.
        """
        if secret_getter is not None:
            self._get_secret = secret_getter
        else:
            from gaol.secrets.store import get_secret_store

            self._store = get_secret_store()
            self._get_secret = self._store.get

    def resolve_value(self, value: str) -> str:
        """Resolve all ${secret:NAME} references in a single value.

        Args:
            value: String that may contain secret references

        Returns:
            String with all secret references replaced with their values

        Raises:
            SecretNotFoundError: If a referenced secret doesn't exist
        """

        def replacer(match: re.Match[str]) -> str:
            secret_name = match.group(1)
            return self._get_secret(secret_name)

        return SECRET_PATTERN.sub(replacer, value)

    def resolve_environment(self, env: dict[str, str]) -> dict[str, str]:
        """Resolve secrets in all environment variable values.

        Args:
            env: Dictionary of environment variables

        Returns:
            New dictionary with all secret references resolved

        Raises:
            SecretNotFoundError: If a referenced secret doesn't exist
        """
        return {key: self.resolve_value(value) for key, value in env.items()}

    def find_secret_refs(self, value: str) -> list[str]:
        """Find all secret references in a value.

        Args:
            value: String to search for secret references

        Returns:
            List of secret names referenced in the value
        """
        return SECRET_PATTERN.findall(value)

    def find_all_secret_refs(self, env: dict[str, str]) -> set[str]:
        """Find all secret references in an environment dictionary.

        Args:
            env: Dictionary of environment variables

        Returns:
            Set of all secret names referenced
        """
        refs: set[str] = set()
        for value in env.values():
            refs.update(self.find_secret_refs(value))
        return refs

    def has_secret_refs(self, value: str) -> bool:
        """Check if a value contains any secret references.

        Args:
            value: String to check

        Returns:
            True if the value contains ${secret:...} references
        """
        return bool(SECRET_PATTERN.search(value))

    def validate_refs(self, env: dict[str, str]) -> list[str]:
        """Validate that all referenced secrets exist.

        Args:
            env: Dictionary of environment variables to validate

        Returns:
            List of missing secret names (empty if all exist)
        """
        from gaol.secrets.store import get_secret_store

        store = get_secret_store()
        refs = self.find_all_secret_refs(env)
        missing: list[str] = []

        for name in refs:
            if not store.exists(name):
                missing.append(name)

        return missing


# Global resolver instance
_resolver: SecretResolver | None = None


def get_secret_resolver() -> SecretResolver:
    """Get the global secret resolver instance."""
    global _resolver
    if _resolver is None:
        _resolver = SecretResolver()
    return _resolver


def resolve_secrets(env: dict[str, str]) -> dict[str, str]:
    """Convenience function to resolve secrets in environment variables.

    Args:
        env: Dictionary of environment variables

    Returns:
        New dictionary with all secret references resolved

    Raises:
        SecretNotFoundError: If a referenced secret doesn't exist
    """
    return get_secret_resolver().resolve_environment(env)


def has_secrets(value: str) -> bool:
    """Check if a value contains secret references.

    Args:
        value: String to check

    Returns:
        True if the value contains ${secret:...} references
    """
    return bool(SECRET_PATTERN.search(value))
