"""
Configuration file for search engines.
Loads search engine definitions from the user's configuration.
"""

import json
import logging
from functools import cache
from typing import Any, Dict, List

from ..utilities.db_utils import get_db_setting

logger = logging.getLogger(__name__)


def _extract_per_engine_config(raw_config: Dict[str, Any]) -> Dict[str, Dict[str, Any]]:
    """
    Converts the "flat" configuration loaded from the settings database into
    individual settings dictionaries for each engine.

    Args:
        raw_config: The raw "flat" configuration.

    Returns:
        Configuration dictionaries indexed by engine name.

    """
    engine_config = {}
    for key, value in raw_config.items():
        engine_name = key.split(".")[0]
        setting_name = ".".join(key.split(".")[1:])
        engine_config.setdefault(engine_name, {})[setting_name] = value

    return engine_config


@cache
def search_config() -> Dict[str, Any]:
    """
    Returns:
        The search engine configuration loaded from the database.

    """
    # Extract search engine definitions
    config_data = get_db_setting("search.engine.web", {})
    search_engines = _extract_per_engine_config(config_data)
    search_engines["auto"] = get_db_setting("search.engine.auto", {})

    logger.info(f"Loaded {len(search_engines)} search engines from configuration file")
    logger.info(f"\n  {', '.join(sorted(search_engines.keys()))} \n")

    # Add alias for 'auto' if it exists
    if "auto" in search_engines and "meta" not in search_engines:
        search_engines["meta"] = search_engines["auto"]

    # Register local document collections
    local_collections_data = get_db_setting("search.engine.local", {})
    local_collections_data = _extract_per_engine_config(local_collections_data)

    for collection, config in local_collections_data.items():
        if not config.get("enabled", True):
            # Search engine is not enabled. Ignore.
            logger.info(f"Ignoring disabled local collection '{collection}'.")
            continue

        if "paths" in config and isinstance(config["paths"], str):
            # This will be saved as a json array.
            try:
                config["paths"] = json.loads(config["paths"])
            except json.decoder.JSONDecodeError:
                logger.error(
                    f"Invalid paths specified for local collection: "
                    f"{config['paths']}"
                )
                config["paths"] = []

        # Create a new dictionary with required search engine fields
        engine_config = {
            "default_params": config,
            "requires_llm": True,
        }
        engine_config_prefix = f"search.engine.local.{collection}"
        engine_config["module_path"] = get_db_setting(
            f"{engine_config_prefix}.module_path",
            "local_deep_research.web_search_engines.engines.search_engine_local",
        )
        engine_config["class_name"] = get_db_setting(
            f"{engine_config_prefix}.class_name",
            "LocalSearchEngine",
        )

        # Copy these specific fields to the top level if they exist
        for field in ["strengths", "weaknesses", "reliability", "description"]:
            if field in config:
                engine_config[field] = config[field]

        search_engines[collection] = engine_config

    logger.info("Registered local document collections as search engines")
    # Ensure the meta search engine is still available at the end if it exists
    if "auto" in search_engines:
        meta_config = search_engines["auto"]
        search_engines["auto"] = meta_config

    return search_engines


@cache
def default_search_engine() -> str:
    """
    Returns:
        The configured default search engine.

    """
    return get_db_setting("search.engine.DEFAULT_SEARCH_ENGINE", "wikipedia")


@cache
def local_search_engines() -> List[str]:
    """
    Returns:
        A list of the enabled local search engines.

    """
    local_collections_data = get_db_setting("search.engine.local", {})
    local_collections_data = _extract_per_engine_config(local_collections_data)

    # Don't include the `local_all` collection.
    local_collections_data.pop("local_all", None)
    # Remove disabled collections.
    local_collections_data = {
        k: v for k, v in local_collections_data.items() if v.get("enabled", True)
    }

    enabled_collections = list(local_collections_data.keys())
    logger.debug(f"Using local collections: {enabled_collections}")
    return enabled_collections
