import os
from pathlib import Path
from types import SimpleNamespace

import yaml

from .user_config import UserConfig


class Config:
    """Main Config Class for application-level configuration."""

    ENVIRONMENT = "dev"
    DEBUG = True
    LOG_LEVEL = "DEBUG"
    FILE_SEARCH_DIRECTORIES = [os.path.expanduser("~")]
    FILE_SEARCH_DIRECTORIES.extend(UserConfig.FILE_SEARCH_DIRECTORIES)

    class Model:
        """Application-level model configuration with inheritance support."""

        # Application-level defaults for all agents
        # TODO: We need to decide on what we want our defaults to be,
        # would we advise shipping with lm_studio or ollama?
        # These can be overridden by user_config.py
        PROVIDER = "ollama_chat"
        MODEL_NAME = "qwen3:latest"

        # Default connection settings (None = no custom connection)
        HOST_ADDRESS = None
        HOST_PORT = None
        HOST_API_KEY = None
        HOST_API_PATH = None  # e.g., "v1" for OpenAI-compatible APIs

        # Application-level agent configurations (usually empty)
        ORCHESTRATOR = {}

        EXPERTS = {"default": {}, "weather": {}, "games": {}, "lighting": {}}

        # Helper method to get merged configuration (app + user)
        @classmethod
        def _get_base_config(cls):
            """Get base configuration with provider and model settings."""
            base_config = {
                "provider": cls.PROVIDER,
                "model_name": cls.MODEL_NAME,
            }

            # Add base connection settings only if they exist
            if hasattr(cls, "HOST_ADDRESS") and cls.HOST_ADDRESS:
                api_path = getattr(cls, "HOST_API_PATH", "") or ""
                base_config["api_base"] = (
                    f"http://{cls.HOST_ADDRESS}:{cls.HOST_PORT}/{api_path}"
                )
            if hasattr(cls, "HOST_API_KEY") and cls.HOST_API_KEY:
                base_config["api_key"] = cls.HOST_API_KEY

            return base_config

        @classmethod
        def _merge_user_config(cls, base_config):
            """Merge user configuration overrides with base config."""
            try:
                user_model_config = UserConfig.Model

                # Override base config with user settings
                if hasattr(user_model_config, "PROVIDER"):
                    base_config["provider"] = user_model_config.PROVIDER
                if hasattr(user_model_config, "MODEL_NAME"):
                    base_config["model_name"] = user_model_config.MODEL_NAME
                if (
                    hasattr(user_model_config, "HOST_ADDRESS")
                    and user_model_config.HOST_ADDRESS
                ):
                    api_path = getattr(user_model_config, "HOST_API_PATH", "") or ""
                    base_config["api_base"] = (
                        f"http://{user_model_config.HOST_ADDRESS}:"
                        f"{user_model_config.HOST_PORT}/{api_path}"
                    )
                if (
                    hasattr(user_model_config, "HOST_API_KEY")
                    and user_model_config.HOST_API_KEY
                ):
                    base_config["api_key"] = user_model_config.HOST_API_KEY

                return user_model_config
            except ImportError:
                return None

        @classmethod
        def get_agent_config(cls, agent_type, agent_name=None):
            """Get configuration for a specific agent type and name.

            Merges application config with user config overrides.

            Args:
                agent_type (str): 'orchestrator' or 'expert'
                agent_name (str): For experts, specific agent name like
                    'weather', 'games'

            Returns:
                dict: Complete configuration for the agent

            """
            base_config = cls._get_base_config()
            user_model_config = cls._merge_user_config(base_config)

            # Get application-level agent config
            if agent_type.lower() == "orchestrator":
                return cls._get_orchestrator_config(base_config, user_model_config)
            elif agent_type.lower() == "expert":
                return cls._get_expert_config(
                    base_config, user_model_config, agent_name
                )
            else:
                return base_config

        @classmethod
        def _get_orchestrator_config(cls, base_config, user_model_config):
            """Get orchestrator-specific configuration."""
            app_agent_config = getattr(cls, "ORCHESTRATOR", {})
            user_agent_config = (
                getattr(user_model_config, "ORCHESTRATOR", {})
                if user_model_config
                else {}
            )
            return {**base_config, **app_agent_config, **user_agent_config}

        @classmethod
        def _get_expert_config(cls, base_config, user_model_config, agent_name):
            """Get expert-specific configuration."""
            app_experts_config = getattr(cls, "EXPERTS", {})
            user_experts_config = (
                getattr(user_model_config, "EXPERTS", {}) if user_model_config else {}
            )

            # Start with default expert config
            app_expert_config = app_experts_config.get("default", {})
            user_expert_default = user_experts_config.get("default", {})
            expert_config = {**app_expert_config, **user_expert_default}

            # If specific agent name provided, merge its config
            if agent_name:
                app_specific_config = app_experts_config.get(agent_name, {})
                user_specific_config = user_experts_config.get(agent_name, {})
                expert_config = {
                    **expert_config,
                    **app_specific_config,
                    **user_specific_config,
                }

            return {**base_config, **expert_config}

    class Weather:
        """Weather-related configuration and mappings."""

        CODE_MAP = {
            0: "Clear sky",
            1: "Mainly clear",
            2: "Partly cloudy",
            3: "Overcast",
            45: "Fog",
            48: "Depositing rime fog",
            51: "Light drizzle",
            53: "Moderate drizzle",
            55: "Dense drizzle",
            56: "Light freezing drizzle",
            57: "Dense freezing drizzle",
            61: "Slight rain",
            63: "Moderate rain",
            65: "Heavy rain",
            66: "Light freezing rain",
            67: "Heavy freezing rain",
            71: "Slight snow",
            73: "Moderate snow",
            75: "Heavy snow",
            77: "Snow grains",
            80: "Slight rain showers",
            81: "Moderate rain showers",
            82: "Violent rain showers",
            85: "Slight snow showers",
            86: "Heavy snow showers",
            95: "Thunderstorm",
            96: "Thunderstorm with slight hail",
            99: "Thunderstorm with heavy hail",
        }

    @classmethod  # Load from YAML
    def load_yaml(cls, file_path="src/config/config.yaml"):
        """Load configuration from YAML file.

        Args:
            file_path (str): Path to the YAML configuration file.

        Returns:
            AppConfig: Configuration instance with loaded settings.

        """
        yaml_file = Path(file_path)
        if not yaml_file.exists():
            default_dict = {"DEBUG": True}
            with open(yaml_file, "w") as f:
                yaml.dump(default_dict, f)

        with open(yaml_file) as f:
            config_data = yaml.safe_load(f)

        # Populate lights and rooms
        lights_data = config_data.get("lights", {})
        rooms_data = config_data.get("rooms", {})

        class Lights:
            pass

        class Rooms:
            pass

        for lightname, light_config in lights_data.items():
            light_obj = SimpleNamespace(light_config)
            setattr(Lights, lightname.replace(" ", "").lower(), light_obj)

        for roomname, room_config in rooms_data.items():
            room_obj = SimpleNamespace(room_config)
            setattr(Rooms, roomname.replace(" ", "").lower(), room_obj)

        cls.Lights = Lights
        cls.Rooms = Rooms


# Load the YAML config when the module is imported
Config.load_yaml()
