"""
Configuration classes for storage backends.

This module provides configuration management for different storage backends,
ensuring proper validation and secure handling of credentials.
"""

import os
from dataclasses import dataclass
from typing import Optional

from django.core.exceptions import ImproperlyConfigured


@dataclass
class CloudinaryConfig:
    """
    Configuration for Cloudinary storage backend.
    
    This dataclass holds all necessary configuration for connecting to and
    using Cloudinary's image storage and transformation services. It includes
    validation to ensure all required fields are provided.
    
    Attributes:
        cloud_name: Cloudinary cloud name (from dashboard)
        api_key: Cloudinary API key (from dashboard)
        api_secret: Cloudinary API secret (from dashboard)
        folder_prefix: Prefix for organizing uploads in folders (e.g., "panjabiz")
    """
    
    cloud_name: str
    api_key: str
    api_secret: str
    folder_prefix: str = "panjabiz"
    
    def __post_init__(self):
        """
        Validate configuration after initialization.
        
        This method is automatically called after the dataclass is created
        to ensure all required fields are properly set.
        
        Raises:
            ImproperlyConfigured: If any required field is missing or empty
        """
        self.validate()
    
    @classmethod
    def from_env(cls) -> 'CloudinaryConfig':
        """
        Create configuration from environment variables.
        
        This method reads Cloudinary configuration from environment variables,
        which is the recommended way to handle credentials in production.
        
        Environment Variables:
            CLOUDINARY_CLOUD_NAME: Your Cloudinary cloud name
            CLOUDINARY_API_KEY: Your Cloudinary API key
            CLOUDINARY_API_SECRET: Your Cloudinary API secret
            CLOUDINARY_FOLDER_PREFIX: Optional folder prefix (default: "panjabiz")
        
        Returns:
            CloudinaryConfig: Configured instance
            
        Raises:
            ImproperlyConfigured: If required environment variables are missing
            
        Example:
            >>> config = CloudinaryConfig.from_env()
            >>> print(config.cloud_name)  # Value from CLOUDINARY_CLOUD_NAME
        """
        cloud_name = os.getenv('CLOUDINARY_CLOUD_NAME')
        api_key = os.getenv('CLOUDINARY_API_KEY')
        api_secret = os.getenv('CLOUDINARY_API_SECRET')
        folder_prefix = os.getenv('CLOUDINARY_FOLDER_PREFIX', 'panjabiz')
        
        if not cloud_name:
            raise ImproperlyConfigured(
                "CLOUDINARY_CLOUD_NAME environment variable is required"
            )
        
        if not api_key:
            raise ImproperlyConfigured(
                "CLOUDINARY_API_KEY environment variable is required"
            )
        
        if not api_secret:
            raise ImproperlyConfigured(
                "CLOUDINARY_API_SECRET environment variable is required"
            )
        
        return cls(
            cloud_name=cloud_name,
            api_key=api_key,
            api_secret=api_secret,
            folder_prefix=folder_prefix
        )
    
    def validate(self) -> None:
        """
        Validate that all required configuration fields are set.
        
        This method checks that all required fields have non-empty values.
        It's called automatically during initialization but can also be
        called manually if configuration is modified.
        
        Raises:
            ImproperlyConfigured: If any required field is missing or empty
        """
        if not self.cloud_name or not self.cloud_name.strip():
            raise ImproperlyConfigured("cloud_name is required and cannot be empty")
        
        if not self.api_key or not self.api_key.strip():
            raise ImproperlyConfigured("api_key is required and cannot be empty")
        
        if not self.api_secret or not self.api_secret.strip():
            raise ImproperlyConfigured("api_secret is required and cannot be empty")
        
        if not self.folder_prefix or not self.folder_prefix.strip():
            raise ImproperlyConfigured("folder_prefix is required and cannot be empty")
    
    @property
    def safe_cloud_name(self) -> str:
        """
        Get cloud name safely for logging.
        
        Returns:
            str: Cloud name (safe to log)
        """
        return self.cloud_name
    
    @property
    def safe_api_key(self) -> str:
        """
        Get API key safely for logging.
        
        Returns:
            str: Masked API key for logging (shows only first 4 characters)
        """
        if len(self.api_key) <= 4:
            return "****"
        return f"{self.api_key[:4]}****"
    
    @property
    def safe_folder_prefix(self) -> str:
        """
        Get folder prefix safely for logging.
        
        Returns:
            str: Folder prefix (safe to log)
        """
        return self.folder_prefix
    
    def __repr__(self) -> str:
        """
        String representation that masks sensitive data.
        
        This ensures that API secrets are never accidentally logged or printed
        in debug output, stack traces, or other diagnostic information.
        
        Returns:
            str: Safe string representation
        """
        return (
            f"CloudinaryConfig("
            f"cloud_name='{self.cloud_name}', "
            f"api_key='{self.safe_api_key}', "
            f"api_secret='****', "
            f"folder_prefix='{self.folder_prefix}'"
            f")"
        )
    
    def __str__(self) -> str:
        """
        String representation that masks sensitive data.
        
        Returns:
            str: Safe string representation
        """
        return self.__repr__()