"""Configuration loader with YAML and environment variable support."""

import os
from pathlib import Path
from typing import Any, Dict, Optional

import yaml
from dotenv import load_dotenv

from src.core.constants import PATHS
from src.core.exceptions import ConfigurationError
from src.logging import get_logger

logger = get_logger(__name__)

# Global config cache
_config: Optional[Dict[str, Any]] = None


def load_config(config_path: Optional[Path] = None) -> Dict[str, Any]:
    """
    Load configuration from YAML files and environment variables.

    Args:
        config_path: Path to main config file (defaults to config/config.yaml)

    Returns:
        Merged configuration dictionary

    Raises:
        ConfigurationError: If configuration cannot be loaded
    """
    global _config

    if _config is not None:
        return _config

    # Load environment variables
    env_path = PATHS["config"].parent / ".env"
    if env_path.exists():
        load_dotenv(env_path)
        logger.debug(f"Loaded environment variables from {env_path}")

    # Load main config
    if config_path is None:
        config_path = PATHS["config"] / "config.yaml"

    if not config_path.exists():
        raise ConfigurationError(
            f"Configuration file not found: {config_path}",
            context={"config_path": str(config_path)},
        )

    try:
        with open(config_path, "r") as f:
            config = yaml.safe_load(f) or {}

        # Substitute environment variables
        config = _substitute_env_vars(config)

        # Load additional config files
        config_dir = config_path.parent
        additional_configs = [
            "logging.yaml",
            "detectors.yaml",
            "models.yaml",
            "trading.yaml",
            "alerts.yaml",
            "database.yaml",
        ]

        for config_file in additional_configs:
            config_file_path = config_dir / config_file
            if config_file_path.exists():
                with open(config_file_path, "r") as f:
                    section_config = yaml.safe_load(f) or {}
                    section_config = _substitute_env_vars(section_config)
                    # Merge into main config
                    section_name = config_file.replace(".yaml", "")
                    config[section_name] = section_config

        _config = config
        logger.info("Configuration loaded successfully")
        return config

    except Exception as e:
        raise ConfigurationError(
            f"Failed to load configuration: {e}",
            context={"config_path": str(config_path)},
        ) from e


def get_config(key: Optional[str] = None, default: Any = None) -> Any:
    """
    Get configuration value by key (dot-separated path).

    Args:
        key: Configuration key (e.g., "trading.session.start_time")
        default: Default value if key not found

    Returns:
        Configuration value or default
    """
    if _config is None:
        load_config()

    if key is None:
        return _config

    keys = key.split(".")
    value = _config

    for k in keys:
        if isinstance(value, dict) and k in value:
            value = value[k]
        else:
            return default

    return value


def _substitute_env_vars(config: Any) -> Any:
    """
    Recursively substitute environment variables in config.

    Args:
        config: Configuration object (dict, list, or primitive)

    Returns:
        Configuration with environment variables substituted
    """
    if isinstance(config, dict):
        return {k: _substitute_env_vars(v) for k, v in config.items()}
    elif isinstance(config, list):
        return [_substitute_env_vars(item) for item in config]
    elif isinstance(config, str):
        # Check for ${VAR} or ${VAR:-default} pattern
        if config.startswith("${") and config.endswith("}"):
            var_expr = config[2:-1]
            if ":-" in var_expr:
                var_name, default_value = var_expr.split(":-", 1)
                return os.getenv(var_name.strip(), default_value.strip())
            else:
                var_name = var_expr.strip()
                value = os.getenv(var_name)
                if value is None:
                    logger.warning(f"Environment variable {var_name} not set")
                    return config  # Return original if not found
                return value
        return config
    else:
        return config

