"""
Configuration management for environment variables and credentials.

This module provides functionality to access environment variables and decrypt credentials.
"""
from dataclasses import dataclass, field
from enum import StrEnum
from typing import Any, Optional
import base64
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend


class InputOutputTypes(StrEnum):
    """Types for input/output configuration."""
    API = 'API'
    QUEUE = 'QUEUE'
    FILA = 'FILA'
    FTP = 'FTP'


@dataclass
class Credential:
    """Credential configuration."""
    key: str
    value: str
    encrypted: bool = False


def decrypt(ciphertext: str, encryption_key: str) -> str:
    """Decrypts a Base64-encoded ciphertext string using AES-256-GCM.

    Args:
        ciphertext (str): The Base64-encoded string containing IV, authentication tag, and ciphertext.
        encryption_key (str): The hexadecimal encryption key.

    Returns:
        str: The decrypted plaintext string.
    """
    key: bytes = bytes.fromhex(encryption_key)
    data: bytes = base64.b64decode(ciphertext)

    iv: bytes = data[:12]
    auth_tag: bytes = data[12:28]
    encrypted: bytes = data[28:]

    decryptor = Cipher(
        algorithms.AES(key),
        modes.GCM(iv, auth_tag),
        backend=default_backend()
    ).decryptor()

    decrypted: bytes = decryptor.update(encrypted) + decryptor.finalize()
    return decrypted.decode("utf-8")


@dataclass
class EnvironmentConfig:
    """Environment configuration object.

    This object contains all configuration from environment variables.
    Access properties using dot notation: config.inputPath, config.get_credential('key'), etc.
    """
    instanceId: str = ""
    executionId: str = ""
    automationName: str = ""
    clientId: str = ""
    userId: str = ""
    outputPath: str = ""
    inputPath: str = ""
    inputMetaData: Optional[dict[str, Any]] = None
    inputType: InputOutputTypes = InputOutputTypes.FTP
    outputType: InputOutputTypes = InputOutputTypes.FTP
    outputMetaData: Optional[dict[str, Any]] = None
    keepAlive: bool = False
    keepAliveInterval: Optional[int] = None
    credentials: list[Credential] = field(default_factory=list)
    _encryption_key: Optional[str] = None

    def get_credential(self, key: str) -> Optional[str]:
        """Get a credential value by key.

        If the credential is encrypted, it will be decrypted automatically.

        Args:
            key (str): The credential key (e.g., 'username', 'password').

        Returns:
            Optional[str]: The credential value (decrypted if needed) or None if not found.
        """
        for cred in self.credentials:
            if cred.key == key:
                if cred.encrypted and self._encryption_key:
                    return decrypt(cred.value, self._encryption_key)
                return cred.value
        return None

    def set_encryption_key(self, key: str) -> None:
        """Set the encryption key for decrypting credentials.

        Args:
            key (str): The encryption key.
        """
        self._encryption_key = key


class DeploymentConfig:
    """Global deployment configuration."""

    def __init__(self) -> None:
        """Initialize deployment configuration."""
        self._config: dict[str, Any] = {}

    def set(self, key: str, value: Any) -> None:
        """Set a configuration value.

        Args:
            key (str): Configuration key.
            value (Any): Configuration value.
        """
        self._config[key] = value

    def get(self, key: str, default: Any = None) -> Any:
        """Get a configuration value.

        Args:
            key (str): Configuration key.
            default (Any, optional): Default value if key not found. Defaults to None.

        Returns:
            Any: Configuration value or default.
        """
        return self._config.get(key, default)

    def update(self, config: dict[str, Any]) -> None:
        """Update multiple configuration values.

        Args:
            config (dict[str, Any]): Dictionary of configuration values.
        """
        self._config.update(config)

    def clear(self) -> None:
        """Clear all configuration."""
        self._config.clear()

    def to_dict(self) -> dict[str, Any]:
        """Get all configuration as dict.

        Returns:
            dict[str, Any]: Copy of all configuration values.
        """
        return self._config.copy()


_deployment_config = DeploymentConfig()


def get_deployment_config() -> DeploymentConfig:
    """Get the global deployment configuration.

    Returns:
        DeploymentConfig: Global deployment configuration instance.
    """
    return _deployment_config


def set_deployment_config(**kwargs: Any) -> None:
    """Set deployment configuration values.

    Args:
        **kwargs (Any): Configuration key-value pairs.
    """
    _deployment_config.update(kwargs)


def _get_config_value(key: str, default: Any = None) -> Any:
    """Get a deployment configuration value (internal use).

    Args:
        key (str): Configuration key.
        default (Any, optional): Default value if key not found. Defaults to None.

    Returns:
        Any: Configuration value or default.
    """
    return _deployment_config.get(key, default)


def get_environment_config() -> Optional[EnvironmentConfig]:
    """Get the full environment configuration object.

    Returns:
        Optional[EnvironmentConfig]: The complete environment config with all fields, or None if not set.

    Example:
        config = get_environment_config()
        if config:
            print(config.inputPath)
            print(config.outputPath)
            username = config.get_credential('username')  # Auto-decrypts if encrypted
    """
    return _deployment_config.get('_env_config')
