"""
Configuration management for xrayradar
"""

import os
from typing import Any, Dict, Optional, Union


class Config:
    """Configuration class for error tracker settings"""

    def __init__(self, **kwargs):
        """
        Initialize configuration

        Args can include:
        - dsn: Data Source Name
        - debug: Enable debug mode
        - environment: Environment name
        - release: Release version
        - server_name: Server name
        - sample_rate: Sampling rate (0.0 to 1.0)
        - max_breadcrumbs: Maximum number of breadcrumbs
        - timeout: HTTP timeout
        - verify_ssl: Whether to verify SSL certificates
        - max_payload_size: Maximum payload size in bytes
        """
        # Set defaults
        self.dsn = kwargs.get('dsn') or os.getenv('XRAYRADAR_DSN')
        self.debug = kwargs.get('debug', False) or os.getenv(
            'XRAYRADAR_DEBUG', '').lower() in ('true', '1', 'yes')
        self.environment = kwargs.get('environment') or os.getenv(
            'XRAYRADAR_ENVIRONMENT', 'development')
        self.release = kwargs.get('release') or os.getenv(
            'XRAYRADAR_RELEASE')
        self.server_name = kwargs.get('server_name') or os.getenv(
            'XRAYRADAR_SERVER_NAME', self._get_default_server_name())
        if 'sample_rate' in kwargs:
            self.sample_rate = float(kwargs.get('sample_rate'))
        else:
            self.sample_rate = float(os.getenv('XRAYRADAR_SAMPLE_RATE', 1.0))

        if 'max_breadcrumbs' in kwargs:
            self.max_breadcrumbs = int(kwargs.get('max_breadcrumbs'))
        else:
            self.max_breadcrumbs = int(
                os.getenv('XRAYRADAR_MAX_BREADCRUMBS', 100))

        # Transport settings
        if 'timeout' in kwargs:
            self.timeout = float(kwargs.get('timeout'))
        else:
            self.timeout = float(os.getenv('XRAYRADAR_TIMEOUT', 10.0))

        if 'verify_ssl' in kwargs:
            self.verify_ssl = bool(kwargs.get('verify_ssl'))
        else:
            self.verify_ssl = os.getenv(
                'XRAYRADAR_VERIFY_SSL', '').lower() not in ('false', '0', 'no')

        if 'max_payload_size' in kwargs:
            self.max_payload_size = int(kwargs.get('max_payload_size'))
        else:
            self.max_payload_size = int(
                os.getenv('XRAYRADAR_MAX_PAYLOAD_SIZE', 100 * 1024))

        # Validate configuration
        self._validate()

    def _get_default_server_name(self) -> str:
        """Get default server name"""
        try:
            import socket
            return socket.gethostname()
        except Exception:
            return 'unknown'

    def _validate(self):
        """Validate configuration values"""
        if self.sample_rate < 0.0 or self.sample_rate > 1.0:
            raise ValueError(
                f"sample_rate must be between 0.0 and 1.0, got {self.sample_rate}. "
                f"Use 0.0 to disable sampling, 1.0 to capture all events, or a value "
                f"in between (e.g., 0.5 for 50% sampling).")

        if self.max_breadcrumbs < 0:
            raise ValueError(
                f"max_breadcrumbs must be non-negative, got {self.max_breadcrumbs}. "
                f"Use a positive integer to limit the number of breadcrumbs stored.")

        if self.timeout <= 0:
            raise ValueError(
                f"timeout must be positive, got {self.timeout}. "
                f"Specify timeout in seconds (e.g., 10.0 for 10 seconds).")

        if self.max_payload_size <= 0:
            raise ValueError(
                f"max_payload_size must be positive, got {self.max_payload_size}. "
                f"Specify size in bytes (e.g., 102400 for 100KB).")

    def to_dict(self) -> Dict[str, Any]:
        """Convert configuration to dictionary"""
        return {
            'dsn': self.dsn,
            'debug': self.debug,
            'environment': self.environment,
            'release': self.release,
            'server_name': self.server_name,
            'sample_rate': self.sample_rate,
            'max_breadcrumbs': self.max_breadcrumbs,
            'timeout': self.timeout,
            'verify_ssl': self.verify_ssl,
            'max_payload_size': self.max_payload_size,
        }

    @classmethod
    def from_dict(cls, config_dict: Dict[str, Any]) -> "Config":
        """Create configuration from dictionary"""
        return cls(**config_dict)

    @classmethod
    def from_env(cls) -> "Config":
        """Create configuration from environment variables"""
        return cls()


def load_config(config_source: Optional[Union[Dict[str, Any], str, Config]] = None) -> Config:
    """
    Load configuration from various sources

    Args:
        config_source: Configuration source - can be:
            - Dict[str, Any]: Configuration dictionary
            - str: Path to configuration file (JSON/YAML)
            - Config: Existing Config instance
            - None: Load from environment variables

    Returns:
        Config instance
    """
    if config_source is None:
        return Config.from_env()
    elif isinstance(config_source, Config):
        return config_source
    elif isinstance(config_source, dict):
        return Config.from_dict(config_source)
    elif isinstance(config_source, str):
        # Load from file
        return _load_config_from_file(config_source)
    else:
        raise TypeError(
            f"Unsupported config source type: {type(config_source).__name__}. "
            f"Expected one of: dict, str (file path), Config instance, or None (environment variables). "
            f"Please provide a valid configuration source.")


def _load_config_from_file(file_path: str) -> Config:
    """Load configuration from file"""
    import json
    import yaml

    if not os.path.exists(file_path):
        raise FileNotFoundError(
            f"Configuration file not found: {file_path}. "
            f"Please ensure the file exists and the path is correct. "
            f"You can create a configuration file or use environment variables instead.")

    with open(file_path, 'r') as f:
        if file_path.endswith('.json'):
            config_dict = json.load(f)
        elif file_path.endswith(('.yml', '.yaml')):
            config_dict = yaml.safe_load(f)
        else:
            ext = os.path.splitext(file_path)[1]
            raise ValueError(
                f"Unsupported configuration file format: '{ext}'. "
                f"Supported formats are: .json, .yaml, .yml. "
                f"Please use one of these formats or load configuration programmatically.")

    return Config.from_dict(config_dict)
