"""This module is used to set the configuration of the system."""

import os
from cognee.base_config import get_base_config
from cognee.modules.cognify.config import get_cognify_config
from cognee.infrastructure.data.chunking.config import get_chunk_config
from cognee.infrastructure.databases.vector import get_vectordb_config
from cognee.infrastructure.databases.graph.config import get_graph_config
from cognee.infrastructure.llm.config import (
    get_llm_config,
)
from cognee.infrastructure.databases.relational import get_relational_config, get_migration_config
from cognee.tasks.translation.config import get_translation_config
from cognee.api.v1.exceptions.exceptions import InvalidConfigAttributeError


class config:
    """
    Configuration namespace for Cognee's runtime settings.

    All methods are static and configure LLM providers, database backends,
    chunking strategies, and storage paths at runtime without requiring
    environment variable changes.

    Example:
        ```python
        import cognee

        cognee.config.set_llm_api_key("your-api-key")
        cognee.config.set_llm_model("gpt-4o-mini")
        cognee.config.system_root_directory("/path/to/system")
        cognee.config.set_vector_db_provider("chromadb")
        ```
    """

    @staticmethod
    def system_root_directory(system_root_directory: str):
        base_config = get_base_config()
        base_config.system_root_directory = system_root_directory

        databases_directory_path = os.path.join(base_config.system_root_directory, "databases")

        relational_config = get_relational_config()
        relational_config.db_path = databases_directory_path

        graph_config = get_graph_config()
        graph_file_name = graph_config.graph_filename
        graph_config.graph_file_path = os.path.join(databases_directory_path, graph_file_name)

        vector_config = get_vectordb_config()
        if vector_config.vector_db_provider == "lancedb":
            vector_config.vector_db_url = os.path.join(databases_directory_path, "cognee.lancedb")

    @staticmethod
    def data_root_directory(data_root_directory: str):
        base_config = get_base_config()
        base_config.data_root_directory = data_root_directory

    @staticmethod
    def monitoring_tool(monitoring_tool: object):
        base_config = get_base_config()
        base_config.monitoring_tool = monitoring_tool

    @staticmethod
    def set_classification_model(classification_model: object):
        cognify_config = get_cognify_config()
        cognify_config.classification_model = classification_model

    @staticmethod
    def set_summarization_model(summarization_model: object):
        cognify_config = get_cognify_config()
        cognify_config.summarization_model = summarization_model

    @staticmethod
    def set_graph_model(graph_model: object):
        graph_config = get_graph_config()
        graph_config.graph_model = graph_model

    @staticmethod
    def set_graph_database_provider(graph_database_provider: str):
        graph_config = get_graph_config()
        graph_config.graph_database_provider = graph_database_provider

    @staticmethod
    def set_llm_provider(llm_provider: str):
        llm_config = get_llm_config()
        llm_config.llm_provider = llm_provider

    @staticmethod
    def set_llm_endpoint(llm_endpoint: str):
        llm_config = get_llm_config()
        llm_config.llm_endpoint = llm_endpoint

    @staticmethod
    def set_llm_model(llm_model: str):
        llm_config = get_llm_config()
        llm_config.llm_model = llm_model

    @staticmethod
    def set_llm_api_key(llm_api_key: str):
        llm_config = get_llm_config()
        llm_config.llm_api_key = llm_api_key

    @staticmethod
    def _update_config(config_obj, config_dict: dict):
        """
        Updates a config object with values from config_dict after attribute validation.
        """
        for key, value in config_dict.items():
            if hasattr(config_obj, key):
                object.__setattr__(config_obj, key, value)
            else:
                raise InvalidConfigAttributeError(attribute=key)

        return config_obj

    @staticmethod
    def set_llm_config(config_dict: dict):
        """
        Updates the llm config with values from config_dict.
        """
        config._update_config(get_llm_config(), config_dict)

    @staticmethod
    def set_chunk_strategy(chunk_strategy: object):
        chunk_config = get_chunk_config()
        chunk_config.chunk_strategy = chunk_strategy

    @staticmethod
    def set_chunk_engine(chunk_engine: object):
        chunk_config = get_chunk_config()
        chunk_config.chunk_engine = chunk_engine

    @staticmethod
    def set_chunk_overlap(chunk_overlap: object):
        chunk_config = get_chunk_config()
        chunk_config.chunk_overlap = chunk_overlap

    @staticmethod
    def set_chunk_size(chunk_size: object):
        chunk_config = get_chunk_config()
        chunk_config.chunk_size = chunk_size

    @staticmethod
    def set_vector_db_provider(vector_db_provider: str):
        vector_db_config = get_vectordb_config()
        vector_db_config.vector_db_provider = vector_db_provider

    @staticmethod
    def set_relational_db_config(config_dict: dict):
        """
        Updates the relational db config with values from config_dict.
        """
        config._update_config(get_relational_config(), config_dict)

    @staticmethod
    def set_migration_db_config(config_dict: dict):
        """
        Updates the relational db config with values from config_dict.
        """
        config._update_config(get_migration_config(), config_dict)

    @staticmethod
    def set_graph_db_config(config_dict: dict) -> None:
        """
        Updates the graph db config with values from config_dict.
        """
        config._update_config(get_graph_config(), config_dict)

    @staticmethod
    def set_vector_db_config(config_dict: dict):
        """
        Updates the vector db config with values from config_dict.
        """
        config._update_config(get_vectordb_config(), config_dict)

    @staticmethod
    def set_vector_db_key(db_key: str):
        vector_db_config = get_vectordb_config()
        vector_db_config.vector_db_key = db_key

    @staticmethod
    def set_vector_db_url(db_url: str):
        vector_db_config = get_vectordb_config()
        vector_db_config.vector_db_url = db_url

    # Translation configuration methods

    @staticmethod
    def set_translation_provider(provider: str):
        """Set the translation provider (llm, google, azure)."""
        translation_config = get_translation_config()
        translation_config.translation_provider = provider

    @staticmethod
    def set_translation_target_language(target_language: str):
        """Set the default target language for translations."""
        translation_config = get_translation_config()
        translation_config.target_language = target_language

    @staticmethod
    def set_translation_config(config_dict: dict):
        """
        Updates the translation config with values from config_dict.
        """
        config._update_config(get_translation_config(), config_dict)

    @staticmethod
    def set(key: str, value):
        """
        Generic setter that maps configuration keys to their specific setter methods.
        This enables CLI commands like 'cognee config set llm_api_key <value>'.
        """
        # Map configuration keys to their setter methods
        setter_mapping = {
            "llm_provider": "set_llm_provider",
            "llm_model": "set_llm_model",
            "llm_api_key": "set_llm_api_key",
            "llm_endpoint": "set_llm_endpoint",
            "graph_database_provider": "set_graph_database_provider",
            "vector_db_provider": "set_vector_db_provider",
            "vector_db_url": "set_vector_db_url",
            "vector_db_key": "set_vector_db_key",
            "chunk_size": "set_chunk_size",
            "chunk_overlap": "set_chunk_overlap",
            "chunk_strategy": "set_chunk_strategy",
            "chunk_engine": "set_chunk_engine",
            "classification_model": "set_classification_model",
            "summarization_model": "set_summarization_model",
            "graph_model": "set_graph_model",
            "system_root_directory": "system_root_directory",
            "data_root_directory": "data_root_directory",
        }

        if key not in setter_mapping:
            raise InvalidConfigAttributeError(attribute=key)

        method_name = setter_mapping[key]
        method = getattr(config, method_name)
        method(value)
