#exonware/xwsystem/src/exonware/xwsystem/runtime/env.py
"""
Company: eXonware.com
Author: eXonware Backend Team
Email: connect@exonware.com
Version: 0.1.0.11
Generation Date: September 04, 2025
Environment management utilities for runtime configuration and detection.
"""

import os
import platform
import sys
from pathlib import Path
from typing import Any, Optional
from ..config.logging_setup import get_logger
logger = get_logger("xwsystem.runtime.env")


class EnvironmentManager:
    """
    Comprehensive environment management for runtime configuration,
    platform detection, and environment variable handling.
    """

    def __init__(self) -> None:
        """Initialize environment manager."""
        self._cache: dict[str, Any] = {}
        self._env_vars: dict[str, str] = dict(os.environ)
    @property

    def platform_info(self) -> dict[str, str]:
        """Get comprehensive platform information."""
        if 'platform_info' not in self._cache:
            self._cache['platform_info'] = {
                'system': platform.system(),
                'release': platform.release(),
                'version': platform.version(),
                'machine': platform.machine(),
                'processor': platform.processor(),
                'architecture': platform.architecture()[0],
                'python_version': platform.python_version(),
                'python_implementation': platform.python_implementation(),
                'node': platform.node(),
            }
        return self._cache['platform_info']
    @property

    def is_windows(self) -> bool:
        """Check if running on Windows using Python's native platform module."""
        return platform.system() == 'Windows'
    @property

    def is_linux(self) -> bool:
        """Check if running on Linux using Python's native platform module."""
        return platform.system() == 'Linux'
    @property

    def is_macos(self) -> bool:
        """Check if running on macOS using Python's native platform module."""
        return platform.system() == 'Darwin'
    @property

    def is_64bit(self) -> bool:
        """Check if running on 64-bit architecture."""
        return platform.architecture()[0] == '64bit'
    @property

    def python_info(self) -> dict[str, Any]:
        """Get Python runtime information."""
        if 'python_info' not in self._cache:
            self._cache['python_info'] = {
                'version': sys.version,
                'version_info': {
                    'major': sys.version_info.major,
                    'minor': sys.version_info.minor,
                    'micro': sys.version_info.micro,
                    'releaselevel': sys.version_info.releaselevel,
                    'serial': sys.version_info.serial,
                },
                'executable': sys.executable,
                'prefix': sys.prefix,
                'exec_prefix': sys.exec_prefix,
                'path': sys.path.copy(),
                'platform': sys.platform,
                'maxsize': sys.maxsize,
                'modules': list(sys.modules.keys()),
            }
        return self._cache['python_info']

    def get_env(self, key: str, default: Optional[str] = None) -> Optional[str]:
        """
        Get environment variable with optional default.
        Args:
            key: Environment variable name
            default: Default value if not found
        Returns:
            Environment variable value or default
        """
        return self._env_vars.get(key, default)

    def get_env_bool(self, key: str, default: bool = False) -> bool:
        """
        Get environment variable as boolean.
        Args:
            key: Environment variable name
            default: Default value if not found
        Returns:
            Boolean value of environment variable
        """
        value = self.get_env(key)
        if value is None:
            return default
        return value.lower() in ('true', '1', 'yes', 'on', 'enabled')

    def get_env_int(self, key: str, default: int = 0) -> int:
        """
        Get environment variable as integer.
        Args:
            key: Environment variable name
            default: Default value if not found
        Returns:
            Integer value of environment variable
        """
        value = self.get_env(key)
        if value is None:
            return default
        try:
            return int(value)
        except ValueError:
            logger.warning(f"Invalid integer value for {key}: {value}, using default: {default}")
            return default

    def get_env_float(self, key: str, default: float = 0.0) -> float:
        """
        Get environment variable as float.
        Args:
            key: Environment variable name
            default: Default value if not found
        Returns:
            Float value of environment variable
        """
        value = self.get_env(key)
        if value is None:
            return default
        try:
            return float(value)
        except ValueError:
            logger.warning(f"Invalid float value for {key}: {value}, using default: {default}")
            return default

    def get_env_list(self, key: str, separator: str = ',', default: Optional[list[str]] = None) -> list[str]:
        """
        Get environment variable as list.
        Args:
            key: Environment variable name
            separator: List item separator
            default: Default value if not found
        Returns:
            List of string values
        """
        value = self.get_env(key)
        if value is None:
            return default or []
        return [item.strip() for item in value.split(separator) if item.strip()]

    def set_env(self, key: str, value: str) -> None:
        """
        Set environment variable.
        Args:
            key: Environment variable name
            value: Environment variable value
        """
        os.environ[key] = value
        self._env_vars[key] = value

    def unset_env(self, key: str) -> bool:
        """
        Unset environment variable.
        Args:
            key: Environment variable name
        Returns:
            True if variable was removed, False if it didn't exist
        """
        if key in os.environ:
            del os.environ[key]
        if key in self._env_vars:
            del self._env_vars[key]
            return True
        return False

    def get_user_home(self) -> Path:
        """Get user home directory."""
        return Path.home()

    def get_user_config_dir(self, app_name: Optional[str] = None) -> Path:
        """
        Get user configuration directory.
        Args:
            app_name: Application name for subdirectory
        Returns:
            Path to configuration directory
        """
        if self.is_windows:
            base = Path(self.get_env('APPDATA', ''))
            if not base:
                base = self.get_user_home() / 'AppData' / 'Roaming'
        elif self.is_macos:
            base = self.get_user_home() / 'Library' / 'Application Support'
        else:  # Linux and others
            base = Path(self.get_env('XDG_CONFIG_HOME', ''))
            if not base:
                base = self.get_user_home() / '.config'
        if app_name:
            base = base / app_name
        return base

    def get_user_data_dir(self, app_name: Optional[str] = None) -> Path:
        """
        Get user data directory.
        Args:
            app_name: Application name for subdirectory
        Returns:
            Path to data directory
        """
        if self.is_windows:
            base = Path(self.get_env('LOCALAPPDATA', ''))
            if not base:
                base = self.get_user_home() / 'AppData' / 'Local'
        elif self.is_macos:
            base = self.get_user_home() / 'Library' / 'Application Support'
        else:  # Linux and others
            base = Path(self.get_env('XDG_DATA_HOME', ''))
            if not base:
                base = self.get_user_home() / '.local' / 'share'
        if app_name:
            base = base / app_name
        return base

    def get_temp_dir(self) -> Path:
        """Get system temporary directory."""
        import tempfile
        return Path(tempfile.gettempdir())

    def get_current_working_dir(self) -> Path:
        """Get current working directory."""
        return Path.cwd()

    def is_development_mode(self) -> bool:
        """Check if running in development mode."""
        return any([
            self.get_env_bool('DEBUG'),
            self.get_env_bool('DEVELOPMENT'),
            self.get_env_bool('DEV'),
            self.get_env('ENVIRONMENT', '').lower() in ('dev', 'development'),
            self.get_env('ENV', '').lower() in ('dev', 'development'),
        ])

    def is_production_mode(self) -> bool:
        """Check if running in production mode."""
        return any([
            self.get_env_bool('PRODUCTION'),
            self.get_env_bool('PROD'),
            self.get_env('ENVIRONMENT', '').lower() in ('prod', 'production'),
            self.get_env('ENV', '').lower() in ('prod', 'production'),
        ])

    def is_testing_mode(self) -> bool:
        """Check if running in testing mode."""
        return any([
            self.get_env_bool('TESTING'),
            self.get_env_bool('TEST'),
            self.get_env('ENVIRONMENT', '').lower() in ('test', 'testing'),
            self.get_env('ENV', '').lower() in ('test', 'testing'),
            'pytest' in sys.modules,
            'unittest' in sys.modules,
        ])

    def get_environment_type(self) -> str:
        """
        Get current environment type.
        Returns:
            Environment type: 'development', 'testing', 'production', or 'unknown'
        """
        if self.is_testing_mode():
            return 'testing'
        elif self.is_development_mode():
            return 'development'
        elif self.is_production_mode():
            return 'production'
        else:
            return 'unknown'

    def get_available_memory_mb(self) -> Optional[float]:
        """
        Get available system memory in MB.
        Returns:
            Available memory in MB or None if cannot determine
        """
        try:
            if self.is_windows:
                import ctypes
                kernel32 = ctypes.windll.kernel32
                c_ulong = ctypes.c_ulong
                class MEMORYSTATUSEX(ctypes.Structure):
                    _fields_ = [
                        ("dwLength", c_ulong),
                        ("dwMemoryLoad", c_ulong),
                        ("ullTotalPhys", ctypes.c_ulonglong),
                        ("ullAvailPhys", ctypes.c_ulonglong),
                        ("ullTotalPageFile", ctypes.c_ulonglong),
                        ("ullAvailPageFile", ctypes.c_ulonglong),
                        ("ullTotalVirtual", ctypes.c_ulonglong),
                        ("ullAvailVirtual", ctypes.c_ulonglong),
                        ("ullAvailExtendedVirtual", ctypes.c_ulonglong),
                    ]
                memoryStatus = MEMORYSTATUSEX()
                memoryStatus.dwLength = ctypes.sizeof(MEMORYSTATUSEX)
                kernel32.GlobalMemoryStatusEx(ctypes.byref(memoryStatus))
                return memoryStatus.ullAvailPhys / (1024 * 1024)
            else:
                # Unix-like systems
                with open('/proc/meminfo', 'r') as f:
                    for line in f:
                        if line.startswith('MemAvailable:'):
                            return int(line.split()[1]) / 1024  # Convert KB to MB
                return None
        except Exception:
            return None

    def get_cpu_count(self) -> int:
        """Get number of CPU cores."""
        return os.cpu_count() or 1

    def get_environment_summary(self) -> dict[str, Any]:
        """Get comprehensive environment summary."""
        return {
            'platform': self.platform_info,
            'python': self.python_info,
            'environment_type': self.get_environment_type(),
            'directories': {
                'home': str(self.get_user_home()),
                'config': str(self.get_user_config_dir()),
                'data': str(self.get_user_data_dir()),
                'temp': str(self.get_temp_dir()),
                'cwd': str(self.get_current_working_dir()),
            },
            'resources': {
                'cpu_count': self.get_cpu_count(),
                'available_memory_mb': self.get_available_memory_mb(),
            },
            'flags': {
                'is_development': self.is_development_mode(),
                'is_production': self.is_production_mode(),
                'is_testing': self.is_testing_mode(),
                'is_64bit': self.is_64bit,
            }
        }
# Global instance for convenience
_env_manager: Optional[EnvironmentManager] = None


def get_environment_manager() -> EnvironmentManager:
    """Get global environment manager instance."""
    global _env_manager
    if _env_manager is None:
        _env_manager = EnvironmentManager()
    return _env_manager
