"""
AUTARCH Configuration Handler
Manages the autarch_settings.conf file for llama.cpp settings
"""

import os
import configparser
from pathlib import Path


class Config:
    """Configuration manager for AUTARCH settings."""

    DEFAULT_CONFIG = {
        'llama': {
            'model_path': '',
            'n_ctx': '4096',
            'n_threads': '4',
            'n_gpu_layers': '0',
            'gpu_backend': 'cpu',
            'temperature': '0.7',
            'top_p': '0.9',
            'top_k': '40',
            'repeat_penalty': '1.1',
            'max_tokens': '2048',
            'seed': '-1',
        },
        'autarch': {
            'first_run': 'true',
            'modules_path': 'modules',
            'verbose': 'false',
            'quiet': 'false',
            'no_banner': 'false',
            'llm_backend': 'local',
        },
        'claude': {
            'api_key': '',
            'model': 'claude-sonnet-4-20250514',
            'max_tokens': '4096',
            'temperature': '0.7',
        },
        'osint': {
            'max_threads': '8',
            'timeout': '8',
            'include_nsfw': 'false',
        },
        'pentest': {
            'max_pipeline_steps': '50',
            'output_chunk_size': '2000',
            'auto_execute': 'false',
            'save_raw_output': 'true',
        },
        'transformers': {
            'model_path': '',
            'device': 'auto',
            'torch_dtype': 'auto',
            'load_in_8bit': 'false',
            'load_in_4bit': 'false',
            'trust_remote_code': 'false',
            'max_tokens': '2048',
            'temperature': '0.7',
            'top_p': '0.9',
            'top_k': '40',
            'repetition_penalty': '1.1',
        },
        'rsf': {
            'install_path': '',
            'enabled': 'true',
            'default_target': '',
            'default_port': '80',
            'execution_timeout': '120',
        },
        'upnp': {
            'enabled': 'true',
            'internal_ip': '10.0.0.26',
            'refresh_hours': '12',
            'mappings': '443:TCP,51820:UDP,8181:TCP',
        },
        'web': {
            'host': '0.0.0.0',
            'port': '8181',
            'secret_key': '',
            'mcp_port': '8081',
        },
        'mcp': {
            'enabled': 'false',
            'auto_start': 'false',
            'transport': 'sse',
            'host': '0.0.0.0',
            'port': '8081',
            'log_level': 'INFO',
            'instructions': 'AUTARCH security framework tools',
            'auth_enabled': 'false',
            'auth_token': '',
            'rate_limit': '',
            'mask_errors': 'false',
            'request_timeout': '120',
            'max_message_size': '10485760',
            'cors_origins': '*',
            'ssl_enabled': 'false',
            'ssl_cert': '',
            'ssl_key': '',
            'disabled_tools': '',
            'nmap_timeout': '120',
            'tcpdump_timeout': '30',
            'whois_timeout': '15',
            'dns_timeout': '10',
            'geoip_timeout': '10',
            'geoip_endpoint': 'http://ip-api.com/json/',
        },
        'revshell': {
            'enabled': 'true',
            'host': '0.0.0.0',
            'port': '17322',
            'auto_start': 'false',
        },
        'slm': {
            'enabled': 'true',
            'backend': 'local',
            'model_path': '',
            'n_ctx': '512',
            'n_gpu_layers': '-1',
            'n_threads': '2',
        },
        'sam': {
            'enabled': 'true',
            'backend': 'local',
            'model_path': '',
            'n_ctx': '2048',
            'n_gpu_layers': '-1',
            'n_threads': '4',
        },
        'lam': {
            'enabled': 'true',
            'backend': 'local',
            'model_path': '',
            'n_ctx': '4096',
            'n_gpu_layers': '-1',
            'n_threads': '4',
        },
        'agents': {
            'backend': 'local',
            'local_max_steps': '20',
            'local_verbose': 'true',
            'claude_enabled': 'false',
            'claude_model': 'claude-sonnet-4-6',
            'claude_max_tokens': '16384',
            'claude_max_steps': '30',
            'openai_enabled': 'false',
            'openai_model': 'gpt-4o',
            'openai_base_url': 'https://api.openai.com/v1',
            'openai_max_tokens': '16384',
            'openai_max_steps': '30',
        },
        'hal_memory': {
            'max_bytes': str(4 * 1024 * 1024 * 1024),  # 4GB default
        },
        'autonomy': {
            'enabled': 'false',
            'monitor_interval': '3',
            'rule_eval_interval': '5',
            'max_concurrent_agents': '3',
            'threat_threshold_auto_respond': '40',
            'log_max_entries': '1000',
        },
    }

    def __init__(self, config_path: str = None):
        """Initialize the configuration manager.

        Args:
            config_path: Path to the configuration file. Defaults to autarch_settings.conf
                        in the framework directory.
        """
        if config_path is None:
            from core.paths import get_config_path
            self.config_path = get_config_path()
        else:
            self.config_path = Path(config_path)

        self.config = configparser.ConfigParser()
        self._load_or_create()

    def _load_or_create(self):
        """Load existing config or create with defaults."""
        if self.config_path.exists():
            self.config.read(self.config_path)
            self._apply_missing_defaults()
        else:
            self._create_default_config()

    def _apply_missing_defaults(self):
        """Add any missing sections/keys from DEFAULT_CONFIG to the loaded config."""
        changed = False
        for section, options in self.DEFAULT_CONFIG.items():
            if section not in self.config:
                self.config[section] = options
                changed = True
            else:
                for key, value in options.items():
                    if key not in self.config[section]:
                        self.config[section][key] = value
                        changed = True
        if changed:
            self.save()

    def _create_default_config(self):
        """Create a default configuration file."""
        for section, options in self.DEFAULT_CONFIG.items():
            self.config[section] = options
        self.save()

    def save(self):
        """Save the current configuration to file."""
        with open(self.config_path, 'w') as f:
            self.config.write(f)

    def get(self, section: str, key: str, fallback=None):
        """Get a configuration value.

        Args:
            section: Configuration section name
            key: Configuration key name
            fallback: Default value if key doesn't exist

        Returns:
            The configuration value or fallback
        """
        value = self.config.get(section, key, fallback=fallback)
        # Strip quotes from values (handles paths with spaces that were quoted)
        if value and isinstance(value, str):
            value = value.strip().strip('"').strip("'")
        return value

    def get_int(self, section: str, key: str, fallback: int = 0) -> int:
        """Get a configuration value as integer."""
        return self.config.getint(section, key, fallback=fallback)

    def get_float(self, section: str, key: str, fallback: float = 0.0) -> float:
        """Get a configuration value as float."""
        return self.config.getfloat(section, key, fallback=fallback)

    def get_bool(self, section: str, key: str, fallback: bool = False) -> bool:
        """Get a configuration value as boolean."""
        return self.config.getboolean(section, key, fallback=fallback)

    def set(self, section: str, key: str, value):
        """Set a configuration value.

        Args:
            section: Configuration section name
            key: Configuration key name
            value: Value to set
        """
        if section not in self.config:
            self.config[section] = {}
        self.config[section][key] = str(value)

    def is_first_run(self) -> bool:
        """Check if this is the first run of AUTARCH."""
        return self.get_bool('autarch', 'first_run', fallback=True)

    def mark_setup_complete(self):
        """Mark the first-time setup as complete."""
        self.set('autarch', 'first_run', 'false')
        self.save()

    def get_llama_settings(self) -> dict:
        """Get all llama.cpp settings as a dictionary.

        Returns:
            Dictionary with llama.cpp settings properly typed
        """
        return {
            'model_path': self.get('llama', 'model_path', ''),
            'n_ctx': self.get_int('llama', 'n_ctx', 4096),
            'n_threads': self.get_int('llama', 'n_threads', 4),
            'n_gpu_layers': self.get_int('llama', 'n_gpu_layers', 0),
            'gpu_backend': self.get('llama', 'gpu_backend', 'cpu'),
            'temperature': self.get_float('llama', 'temperature', 0.7),
            'top_p': self.get_float('llama', 'top_p', 0.9),
            'top_k': self.get_int('llama', 'top_k', 40),
            'repeat_penalty': self.get_float('llama', 'repeat_penalty', 1.1),
            'max_tokens': self.get_int('llama', 'max_tokens', 2048),
            'seed': self.get_int('llama', 'seed', -1),
        }

    def get_osint_settings(self) -> dict:
        """Get all OSINT settings as a dictionary.

        Returns:
            Dictionary with OSINT settings properly typed
        """
        return {
            'max_threads': self.get_int('osint', 'max_threads', 8),
            'timeout': self.get_int('osint', 'timeout', 8),
            'include_nsfw': self.get_bool('osint', 'include_nsfw', False),
        }

    def get_pentest_settings(self) -> dict:
        """Get all pentest pipeline settings as a dictionary.

        Returns:
            Dictionary with pentest settings properly typed
        """
        return {
            'max_pipeline_steps': self.get_int('pentest', 'max_pipeline_steps', 50),
            'output_chunk_size': self.get_int('pentest', 'output_chunk_size', 2000),
            'auto_execute': self.get_bool('pentest', 'auto_execute', False),
            'save_raw_output': self.get_bool('pentest', 'save_raw_output', True),
        }

    def _get_secret(self, key: str, fallback_section: str = '', fallback_key: str = 'api_key') -> str:
        """Get a secret from the vault, falling back to plaintext config.

        This allows a gradual migration: existing plaintext keys still work,
        but new keys go to the vault. When a plaintext key is found, it's
        automatically migrated to the vault on next save.
        """
        try:
            from core.vault import get_vault
            vault = get_vault()
            val = vault.get(key, '')
            if val:
                return val
        except Exception:
            pass
        # Fallback to plaintext config
        if fallback_section:
            return self.get(fallback_section, fallback_key, '')
        return ''

    def _set_secret(self, key: str, value: str, config_section: str = '', config_key: str = 'api_key'):
        """Store a secret in the vault and clear the plaintext config value."""
        if not value:
            return
        try:
            from core.vault import get_vault
            vault = get_vault()
            vault.set(key, value)
            # Clear plaintext from config file for security
            if config_section:
                self.set(config_section, config_key, '')
        except Exception:
            # Vault not available — store in config as before
            if config_section:
                self.set(config_section, config_key, value)

    def get_claude_settings(self) -> dict:
        """Get all Claude API settings as a dictionary.

        Returns:
            Dictionary with Claude API settings properly typed
        """
        return {
            'api_key': self._get_secret('claude_api_key', 'claude', 'api_key'),
            'model': self.get('claude', 'model', 'claude-sonnet-4-20250514'),
            'max_tokens': self.get_int('claude', 'max_tokens', 4096),
            'temperature': self.get_float('claude', 'temperature', 0.7),
        }

    def get_transformers_settings(self) -> dict:
        """Get all transformers/safetensors settings as a dictionary.

        Returns:
            Dictionary with transformers settings properly typed
        """
        return {
            'model_path': self.get('transformers', 'model_path', ''),
            'device': self.get('transformers', 'device', 'auto'),
            'torch_dtype': self.get('transformers', 'torch_dtype', 'auto'),
            'load_in_8bit': self.get_bool('transformers', 'load_in_8bit', False),
            'load_in_4bit': self.get_bool('transformers', 'load_in_4bit', False),
            'llm_int8_enable_fp32_cpu_offload': self.get_bool('transformers', 'llm_int8_enable_fp32_cpu_offload', False),
            'device_map': self.get('transformers', 'device_map', 'auto'),
            'trust_remote_code': self.get_bool('transformers', 'trust_remote_code', False),
            'max_tokens': self.get_int('transformers', 'max_tokens', 2048),
            'temperature': self.get_float('transformers', 'temperature', 0.7),
            'top_p': self.get_float('transformers', 'top_p', 0.9),
            'top_k': self.get_int('transformers', 'top_k', 40),
            'repetition_penalty': self.get_float('transformers', 'repetition_penalty', 1.1),
        }

    def get_huggingface_settings(self) -> dict:
        """Get all HuggingFace Inference API settings as a dictionary."""
        return {
            'api_key': self._get_secret('huggingface_api_key', 'huggingface', 'api_key'),
            'model': self.get('huggingface', 'model', 'mistralai/Mistral-7B-Instruct-v0.3'),
            'endpoint': self.get('huggingface', 'endpoint', ''),
            'provider': self.get('huggingface', 'provider', 'auto'),
            'max_tokens': self.get_int('huggingface', 'max_tokens', 1024),
            'temperature': self.get_float('huggingface', 'temperature', 0.7),
            'top_p': self.get_float('huggingface', 'top_p', 0.9),
            'top_k': self.get_int('huggingface', 'top_k', 40),
            'repetition_penalty': self.get_float('huggingface', 'repetition_penalty', 1.1),
            'do_sample': self.get_bool('huggingface', 'do_sample', True),
            'seed': self.get_int('huggingface', 'seed', -1),
            'stop_sequences': self.get('huggingface', 'stop_sequences', ''),
        }

    def get_openai_settings(self) -> dict:
        """Get all OpenAI API settings as a dictionary."""
        return {
            'api_key': self._get_secret('openai_api_key', 'openai', 'api_key'),
            'base_url': self.get('openai', 'base_url', 'https://api.openai.com/v1'),
            'model': self.get('openai', 'model', 'gpt-4o'),
            'max_tokens': self.get_int('openai', 'max_tokens', 4096),
            'temperature': self.get_float('openai', 'temperature', 0.7),
            'top_p': self.get_float('openai', 'top_p', 1.0),
            'frequency_penalty': self.get_float('openai', 'frequency_penalty', 0.0),
            'presence_penalty': self.get_float('openai', 'presence_penalty', 0.0),
        }

    def get_rsf_settings(self) -> dict:
        """Get all RouterSploit settings as a dictionary.

        Returns:
            Dictionary with RSF settings properly typed
        """
        return {
            'install_path': self.get('rsf', 'install_path', ''),
            'enabled': self.get_bool('rsf', 'enabled', True),
            'default_target': self.get('rsf', 'default_target', ''),
            'default_port': self.get('rsf', 'default_port', '80'),
            'execution_timeout': self.get_int('rsf', 'execution_timeout', 120),
        }

    def get_upnp_settings(self) -> dict:
        """Get all UPnP settings as a dictionary."""
        return {
            'enabled': self.get_bool('upnp', 'enabled', True),
            'internal_ip': self.get('upnp', 'internal_ip', '10.0.0.26'),
            'refresh_hours': self.get_int('upnp', 'refresh_hours', 12),
            'mappings': self.get('upnp', 'mappings', ''),
        }

    def get_mcp_settings(self) -> dict:
        """Get all MCP server settings as a dictionary."""
        return {
            'enabled': self.get_bool('mcp', 'enabled', False),
            'auto_start': self.get_bool('mcp', 'auto_start', False),
            'transport': self.get('mcp', 'transport', 'sse'),
            'host': self.get('mcp', 'host', '0.0.0.0'),
            'port': self.get_int('mcp', 'port', 8081),
            'log_level': self.get('mcp', 'log_level', 'INFO'),
            'instructions': self.get('mcp', 'instructions', 'AUTARCH security framework tools'),
            'auth_enabled': self.get_bool('mcp', 'auth_enabled', False),
            'auth_token': self.get('mcp', 'auth_token', ''),
            'rate_limit': self.get('mcp', 'rate_limit', ''),
            'mask_errors': self.get_bool('mcp', 'mask_errors', False),
            'request_timeout': self.get_int('mcp', 'request_timeout', 120),
            'max_message_size': self.get_int('mcp', 'max_message_size', 10485760),
            'cors_origins': self.get('mcp', 'cors_origins', '*'),
            'ssl_enabled': self.get_bool('mcp', 'ssl_enabled', False),
            'ssl_cert': self.get('mcp', 'ssl_cert', ''),
            'ssl_key': self.get('mcp', 'ssl_key', ''),
            'disabled_tools': self.get('mcp', 'disabled_tools', ''),
            'nmap_timeout': self.get_int('mcp', 'nmap_timeout', 120),
            'tcpdump_timeout': self.get_int('mcp', 'tcpdump_timeout', 30),
            'whois_timeout': self.get_int('mcp', 'whois_timeout', 15),
            'dns_timeout': self.get_int('mcp', 'dns_timeout', 10),
            'geoip_timeout': self.get_int('mcp', 'geoip_timeout', 10),
            'geoip_endpoint': self.get('mcp', 'geoip_endpoint', 'http://ip-api.com/json/'),
        }

    def get_revshell_settings(self) -> dict:
        """Get all reverse shell settings as a dictionary."""
        return {
            'enabled': self.get_bool('revshell', 'enabled', True),
            'host': self.get('revshell', 'host', '0.0.0.0'),
            'port': self.get_int('revshell', 'port', 17322),
            'auto_start': self.get_bool('revshell', 'auto_start', False),
        }

    def get_mcp_settings(self) -> dict:
        """Get MCP server settings."""
        return {
            'enabled': self.get_bool('mcp', 'enabled', False),
            'auto_start': self.get_bool('mcp', 'auto_start', False),
            'transport': self.get('mcp', 'transport', 'sse'),
            'host': self.get('mcp', 'host', '0.0.0.0'),
            'port': self.get_int('mcp', 'port', 8081),
            'log_level': self.get('mcp', 'log_level', 'INFO'),
            'instructions': self.get('mcp', 'instructions', 'AUTARCH security framework tools'),
            'auth_enabled': self.get_bool('mcp', 'auth_enabled', False),
            'auth_token': self.get('mcp', 'auth_token', ''),
            'rate_limit': self.get('mcp', 'rate_limit', ''),
            'mask_errors': self.get_bool('mcp', 'mask_errors', False),
            'request_timeout': self.get_int('mcp', 'request_timeout', 120),
            'max_message_size': self.get_int('mcp', 'max_message_size', 10485760),
            'cors_origins': self.get('mcp', 'cors_origins', '*'),
            'ssl_enabled': self.get_bool('mcp', 'ssl_enabled', False),
            'ssl_cert': self.get('mcp', 'ssl_cert', ''),
            'ssl_key': self.get('mcp', 'ssl_key', ''),
            'disabled_tools': self.get('mcp', 'disabled_tools', ''),
            'nmap_timeout': self.get_int('mcp', 'nmap_timeout', 120),
            'tcpdump_timeout': self.get_int('mcp', 'tcpdump_timeout', 30),
            'whois_timeout': self.get_int('mcp', 'whois_timeout', 15),
            'dns_timeout': self.get_int('mcp', 'dns_timeout', 10),
            'geoip_timeout': self.get_int('mcp', 'geoip_timeout', 10),
            'geoip_endpoint': self.get('mcp', 'geoip_endpoint', 'http://ip-api.com/json/'),
        }

    def get_tier_settings(self, tier: str) -> dict:
        """Get settings for a model tier (slm, sam, lam)."""
        return {
            'enabled': self.get_bool(tier, 'enabled', True),
            'backend': self.get(tier, 'backend', 'local'),
            'model_path': self.get(tier, 'model_path', ''),
            'n_ctx': self.get_int(tier, 'n_ctx', 2048),
            'n_gpu_layers': self.get_int(tier, 'n_gpu_layers', -1),
            'n_threads': self.get_int(tier, 'n_threads', 4),
        }

    def get_slm_settings(self) -> dict:
        """Get Small Language Model tier settings."""
        return self.get_tier_settings('slm')

    def get_sam_settings(self) -> dict:
        """Get Small Action Model tier settings."""
        return self.get_tier_settings('sam')

    def get_lam_settings(self) -> dict:
        """Get Large Action Model tier settings."""
        return self.get_tier_settings('lam')

    def get_autonomy_settings(self) -> dict:
        """Get autonomy daemon settings."""
        return {
            'enabled': self.get_bool('autonomy', 'enabled', False),
            'monitor_interval': self.get_int('autonomy', 'monitor_interval', 3),
            'rule_eval_interval': self.get_int('autonomy', 'rule_eval_interval', 5),
            'max_concurrent_agents': self.get_int('autonomy', 'max_concurrent_agents', 3),
            'threat_threshold_auto_respond': self.get_int('autonomy', 'threat_threshold_auto_respond', 40),
            'log_max_entries': self.get_int('autonomy', 'log_max_entries', 1000),
        }

    def get_agents_settings(self) -> dict:
        """Get agent configuration settings."""
        return {
            'backend': self.get('agents', 'backend', 'local'),
            'local_max_steps': self.get_int('agents', 'local_max_steps', 20),
            'local_verbose': self.get_bool('agents', 'local_verbose', True),
            'claude_enabled': self.get_bool('agents', 'claude_enabled', False),
            'claude_model': self.get('agents', 'claude_model', 'claude-sonnet-4-6'),
            'claude_max_tokens': self.get_int('agents', 'claude_max_tokens', 16384),
            'claude_max_steps': self.get_int('agents', 'claude_max_steps', 30),
            'openai_enabled': self.get_bool('agents', 'openai_enabled', False),
            'openai_model': self.get('agents', 'openai_model', 'gpt-4o'),
            'openai_base_url': self.get('agents', 'openai_base_url', 'https://api.openai.com/v1'),
            'openai_max_tokens': self.get_int('agents', 'openai_max_tokens', 16384),
            'openai_max_steps': self.get_int('agents', 'openai_max_steps', 30),
        }

    @staticmethod
    def get_templates_dir() -> Path:
        """Get the path to the configuration templates directory."""
        from core.paths import get_templates_dir
        return get_templates_dir()

    @staticmethod
    def get_custom_configs_dir() -> Path:
        """Get the path to the custom user configurations directory."""
        from core.paths import get_custom_configs_dir
        return get_custom_configs_dir()

    def list_hardware_templates(self) -> list:
        """List available hardware configuration templates.

        Returns:
            List of tuples: (template_id, display_name, description, filename)
        """
        templates = [
            ('nvidia_4070_mobile', 'NVIDIA RTX 4070 Mobile', '8GB VRAM, CUDA, optimal for 7B-13B models', 'nvidia_4070_mobile.conf'),
            ('amd_rx6700xt', 'AMD Radeon RX 6700 XT', '12GB VRAM, ROCm, optimal for 7B-13B models', 'amd_rx6700xt.conf'),
            ('orangepi5plus_cpu', 'Orange Pi 5 Plus (CPU)', 'RK3588 ARM64, CPU-only, for quantized models', 'orangepi5plus_cpu.conf'),
            ('orangepi5plus_mali', 'Orange Pi 5 Plus (Mali GPU)', 'EXPERIMENTAL - Mali-G610 OpenCL acceleration', 'orangepi5plus_mali.conf'),
        ]
        return templates

    def list_custom_configs(self) -> list:
        """List user-saved custom configurations.

        Returns:
            List of tuples: (name, filepath)
        """
        custom_dir = self.get_custom_configs_dir()
        configs = []
        for conf_file in custom_dir.glob('*.conf'):
            name = conf_file.stem.replace('_', ' ').title()
            configs.append((name, conf_file))
        return configs

    def load_template(self, template_id: str) -> bool:
        """Load a hardware template into the current configuration.

        Args:
            template_id: The template identifier (e.g., 'nvidia_4070_mobile')

        Returns:
            True if loaded successfully, False otherwise
        """
        templates = {t[0]: t[3] for t in self.list_hardware_templates()}
        if template_id not in templates:
            return False

        template_path = self.get_templates_dir() / templates[template_id]
        if not template_path.exists():
            return False

        return self._load_llm_settings_from_file(template_path)

    def load_custom_config(self, filepath: Path) -> bool:
        """Load a custom configuration file.

        Args:
            filepath: Path to the custom configuration file

        Returns:
            True if loaded successfully, False otherwise
        """
        if not filepath.exists():
            return False
        return self._load_llm_settings_from_file(filepath)

    def _load_llm_settings_from_file(self, filepath: Path) -> bool:
        """Load LLM settings (llama and transformers sections) from a file.

        Preserves model_path from current config (doesn't overwrite).

        Args:
            filepath: Path to the configuration file

        Returns:
            True if loaded successfully, False otherwise
        """
        try:
            template_config = configparser.ConfigParser()
            template_config.read(filepath)

            # Preserve current model paths
            current_llama_path = self.get('llama', 'model_path', '')
            current_transformers_path = self.get('transformers', 'model_path', '')

            # Load llama section
            if 'llama' in template_config:
                for key, value in template_config['llama'].items():
                    if key != 'model_path':  # Preserve current model path
                        self.set('llama', key, value)
                # Restore model path
                if current_llama_path:
                    self.set('llama', 'model_path', current_llama_path)

            # Load transformers section
            if 'transformers' in template_config:
                for key, value in template_config['transformers'].items():
                    if key != 'model_path':  # Preserve current model path
                        self.set('transformers', key, value)
                # Restore model path
                if current_transformers_path:
                    self.set('transformers', 'model_path', current_transformers_path)

            self.save()
            return True
        except Exception:
            return False

    def save_custom_config(self, name: str) -> Path:
        """Save current LLM settings to a custom configuration file.

        Args:
            name: Name for the custom configuration (will be sanitized)

        Returns:
            Path to the saved configuration file
        """
        # Sanitize name for filename
        safe_name = ''.join(c if c.isalnum() or c in '-_' else '_' for c in name.lower())
        safe_name = safe_name.strip('_')
        if not safe_name:
            safe_name = 'custom_config'

        custom_dir = self.get_custom_configs_dir()
        filepath = custom_dir / f'{safe_name}.conf'

        # Create config with just LLM settings
        custom_config = configparser.ConfigParser()

        # Save llama settings
        custom_config['llama'] = {}
        for key in self.DEFAULT_CONFIG['llama'].keys():
            value = self.get('llama', key, '')
            if value:
                custom_config['llama'][key] = str(value)

        # Save transformers settings
        custom_config['transformers'] = {}
        for key in self.DEFAULT_CONFIG['transformers'].keys():
            value = self.get('transformers', key, '')
            if value:
                custom_config['transformers'][key] = str(value)

        # Add header comment
        with open(filepath, 'w') as f:
            f.write(f'# AUTARCH Custom LLM Configuration\n')
            f.write(f'# Name: {name}\n')
            f.write(f'# Saved: {Path(self.config_path).name}\n')
            f.write('#\n\n')
            custom_config.write(f)

        return filepath

    def delete_custom_config(self, filepath: Path) -> bool:
        """Delete a custom configuration file.

        Args:
            filepath: Path to the custom configuration file

        Returns:
            True if deleted successfully, False otherwise
        """
        try:
            if filepath.exists() and filepath.parent == self.get_custom_configs_dir():
                filepath.unlink()
                return True
        except Exception:
            pass
        return False


# Global config instance
_config = None


def get_config() -> Config:
    """Get the global configuration instance."""
    global _config
    if _config is None:
        _config = Config()
    return _config
