"""Configuration management system with YAML and environment variables."""

import os
import yaml
from pathlib import Path
from typing import Any, Dict, Optional
from dotenv import load_dotenv

# Load environment variables
load_dotenv()


class Config:
    """Configuration manager with XDG directory support."""
    
    def __init__(self, config_file: Optional[str] = None):
        """Initialize configuration manager.
        
        Args:
            config_file: Optional path to config file. If None, uses XDG default.
        """
        self._setup_xdg_directories()
        
        # Determine config file priority:
        # 1. Explicit argument
        # 2. Local project config (dev mode)
        # 3. XDG config (user mode)
        
        local_config = Path(__file__).parent.parent.parent / "config" / "config.yaml"
        
        if config_file:
            self.config_file = Path(config_file)
        elif local_config.exists():
            self.config_file = local_config
        else:
            self.config_file = self.config_dir / "config.yaml"
            
        self._config: Dict[str, Any] = {}
        self._load_config()
    
    def _setup_xdg_directories(self):
        """Set up XDG Base Directory Specification directories."""
        home = Path.home()
        
        # XDG_CONFIG_HOME or default
        xdg_config = os.getenv("XDG_CONFIG_HOME", home / ".config")
        self.config_dir = Path(xdg_config) / "crypto_trader"
        self.config_dir.mkdir(parents=True, exist_ok=True)
        
        # XDG_DATA_HOME or default
        xdg_data = os.getenv("XDG_DATA_HOME", home / ".local" / "share")
        self.data_dir = Path(xdg_data) / "crypto_trader"
        self.data_dir.mkdir(parents=True, exist_ok=True)
        
        # Create subdirectories
        (self.data_dir / "historical").mkdir(exist_ok=True)
        (self.data_dir / "backups").mkdir(exist_ok=True)
        (self.data_dir / "logs").mkdir(exist_ok=True)
        
        # XDG_CACHE_HOME or default
        xdg_cache = os.getenv("XDG_CACHE_HOME", home / ".cache")
        self.cache_dir = Path(xdg_cache) / "crypto_trader"
        self.cache_dir.mkdir(parents=True, exist_ok=True)
    
    def _load_config(self):
        """Load configuration from YAML file and environment variables."""
        # Load defaults
        default_config = self._get_default_config()
        self._config = default_config.copy()
        
        # Load from file if it exists
        if self.config_file.exists():
            with open(self.config_file, 'r') as f:
                file_config = yaml.safe_load(f) or {}
                self._config.update(file_config)
        
        # Override with environment variables
        self._load_from_env()
    
    def _get_default_config(self) -> Dict[str, Any]:
        """Get default configuration."""
        return {
            "app": {
                "name": "Crypto Trader",
                "version": "0.1.0",
            },
            "database": {
                "type": "postgresql",
                "url": None,  # For PostgreSQL
            },
            "logging": {
                "level": os.getenv("LOG_LEVEL", "INFO"),
                "dir": str(self.data_dir / "logs"),
                "retention_days": 30,
                "rotation": "daily",
            },
            "paper_trading": {
                "enabled": True,
                "default_capital": float(os.getenv("PAPER_TRADING_CAPITAL", "100.0")),
            },
            "updates": {
                "check_on_startup": os.getenv("UPDATE_CHECK_ON_STARTUP", "true").lower() == "true",
                "repository_url": os.getenv("UPDATE_REPOSITORY_URL", ""),
            },
            "exchanges": {},
            "strategies": {
                "default_timeframe": "1h",
            },
            "risk": {
                "max_drawdown_percent": 20.0,
                "daily_loss_limit_percent": 5.0,
                "position_size_percent": 2.0,
            },
            "trading": {
                "default_fees": {
                    "maker": 0.001,  # 0.1%
                    "taker": 0.001,  # 0.1%
                    "minimum": 0.0,
                },
                "exchanges": {},
            },
            "data_providers": {
                "primary": [
                    {"name": "kraken", "enabled": True, "priority": 1},
                    {"name": "coinbase", "enabled": True, "priority": 2},
                    {"name": "binance", "enabled": True, "priority": 3},
                ],
                "fallback": {
                    "name": "coingecko",
                    "enabled": True,
                    "api_key": "",
                },
                "caching": {
                    "ticker_ttl": 2,  # seconds
                    "ohlcv_ttl": 60,  # seconds
                    "max_cache_size": 1000,
                },
                "websocket": {
                    "enabled": True,
                    "reconnect_interval": 5,  # seconds
                    "ping_interval": 30,  # seconds
                },
            },
            "redis": {
                "host": os.getenv("REDIS_HOST", "127.0.0.1"),
                "port": int(os.getenv("REDIS_PORT", 6379)),
                "db": int(os.getenv("REDIS_DB", 0)),
                "password": os.getenv("REDIS_PASSWORD", None),
                "socket_connect_timeout": 5,
            },
            "celery": {
                "broker_url": os.getenv("CELERY_BROKER_URL", "redis://127.0.0.1:6379/0"),
                "result_backend": os.getenv("CELERY_RESULT_BACKEND", "redis://127.0.0.1:6379/0"),
            },
        }
    
    def _load_from_env(self):
        """Load configuration from environment variables."""
        # Database
        if db_url := os.getenv("DATABASE_URL"):
            self._config["database"]["url"] = db_url
            self._config["database"]["type"] = "postgresql"
        
        # Logging
        if log_level := os.getenv("LOG_LEVEL"):
            self._config["logging"]["level"] = log_level
        if log_dir := os.getenv("LOG_DIR"):
            self._config["logging"]["dir"] = log_dir
        
        # Paper trading
        if capital := os.getenv("PAPER_TRADING_CAPITAL"):
            self._config["paper_trading"]["default_capital"] = float(capital)
    
    def get(self, key: str, default: Any = None) -> Any:
        """Get configuration value using dot notation.
        
        Args:
            key: Configuration key (e.g., "database.path")
            default: Default value if key not found
            
        Returns:
            Configuration value or default
        """
        keys = key.split(".")
        value = self._config
        for k in keys:
            if isinstance(value, dict):
                value = value.get(k)
                if value is None:
                    return default
            else:
                return default
        return value
    
    def set(self, key: str, value: Any):
        """Set configuration value using dot notation.
        
        Args:
            key: Configuration key (e.g., "database.path")
            value: Value to set
        """
        keys = key.split(".")
        config = self._config
        for k in keys[:-1]:
            if k not in config:
                config[k] = {}
            config = config[k]
        config[keys[-1]] = value
    
    def save(self):
        """Save configuration to file."""
        with open(self.config_file, 'w') as f:
            yaml.dump(self._config, f, default_flow_style=False, sort_keys=False)
    
    @property
    def config_dir(self) -> Path:
        """Get config directory path."""
        return self._config_dir
    
    @config_dir.setter
    def config_dir(self, value: Path):
        """Set config directory."""
        self._config_dir = value
    
    @property
    def data_dir(self) -> Path:
        """Get data directory path."""
        return self._data_dir
    
    @data_dir.setter
    def data_dir(self, value: Path):
        """Set data directory."""
        self._data_dir = value
    
    @property
    def cache_dir(self) -> Path:
        """Get cache directory path."""
        return self._cache_dir
    
    @cache_dir.setter
    def cache_dir(self, value: Path):
        """Set cache directory."""
        self._cache_dir = value


# Global config instance
_config_instance: Optional[Config] = None


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

