"""
Dynamic module mocking utilities - inspired by scottvr's approach.

This module provides utilities for creating mock modules dynamically during tests.
"""

import sys
import types
from typing import Any, Dict, Optional
from unittest.mock import Mock


def create_mock_module(
    module_name: str, attributes: Dict[str, Any]
) -> types.ModuleType:
    """
    Create a mock module with specified attributes.

    Args:
        module_name: Name of the module to create
        attributes: Dictionary of attributes to add to the module

    Returns:
        Mock module instance
    """
    mock_module = types.ModuleType(module_name)

    for key, value in attributes.items():
        setattr(mock_module, key, value)

    return mock_module


def patch_module(monkeypatch, module_path: str, mock_module: types.ModuleType):
    """
    Patch a module in the import system.

    Args:
        monkeypatch: pytest monkeypatch fixture
        module_path: Full path to the module (e.g., 'src.local_deep_research.config.llm_config')
        mock_module: The mock module to use
    """
    monkeypatch.setitem(sys.modules, module_path, mock_module)

    # Also patch direct imports
    parts = module_path.split(".")
    if len(parts) > 1:
        parent_path = ".".join(parts[:-1])
        module_name = parts[-1]
        if parent_path in sys.modules:
            monkeypatch.setattr(f"{parent_path}.{module_name}", mock_module)


def create_mock_llm_config(monkeypatch):
    """
    Create and patch a complete mock llm_config module.

    This is useful for testing components that depend on llm_config
    without requiring actual LLM connections.
    """

    def get_llm(*args, **kwargs):
        mock = Mock()
        mock.invoke.return_value = Mock(content="Mocked LLM response")
        return mock

    def get_available_providers():
        return {
            "ollama": "Ollama (local models)",
            "openai": "OpenAI API",
            "anthropic": "Anthropic Claude",
            "none": "No LLM (testing)",
        }

    attributes = {
        "get_llm": get_llm,
        "get_available_providers": get_available_providers,
        "VALID_PROVIDERS": [
            "ollama",
            "openai",
            "anthropic",
            "vllm",
            "openai_endpoint",
            "lmstudio",
            "llamacpp",
            "none",
        ],
        "AVAILABLE_PROVIDERS": get_available_providers(),
        "DEFAULT_PROVIDER": "ollama",
        "DEFAULT_MODEL": "gemma3:12b",
        "DEFAULT_TEMPERATURE": 0.7,
        "DEFAULT_MAX_TOKENS": 4096,
    }

    mock_module = create_mock_module("llm_config", attributes)
    patch_module(
        monkeypatch, "src.local_deep_research.config.llm_config", mock_module
    )

    return mock_module


def create_mock_search_config(monkeypatch):
    """
    Create and patch a complete mock search_config module.
    """

    def get_search(search_tool: Optional[str] = None, **kwargs):
        mock = Mock()
        mock.run.return_value = [
            {
                "title": "Mock Search Result",
                "link": "https://example.com/mock",
                "snippet": "This is a mock search result",
            }
        ]
        return mock

    def get_available_search_tools():
        return {
            "searxng": "SearXNG Meta Search",
            "ddg": "DuckDuckGo",
            "google_pse": "Google Programmable Search Engine",
            "none": "No search (testing)",
        }

    attributes = {
        "get_search": get_search,
        "get_available_search_tools": get_available_search_tools,
        "AVAILABLE_SEARCH_TOOLS": get_available_search_tools(),
        "DEFAULT_SEARCH_TOOL": "searxng",
        "DEFAULT_MAX_RESULTS": 50,
    }

    mock_module = create_mock_module("search_config", attributes)
    patch_module(
        monkeypatch, "src.local_deep_research.config.search_config", mock_module
    )

    return mock_module


def create_mock_db_utils(
    monkeypatch, settings: Optional[Dict[str, Any]] = None
):
    """
    Create and patch a mock db_utils module with configurable settings.
    """
    default_settings = {
        "general.enable_fact_checking": True,
        "llm.provider": "ollama",
        "llm.model": "gemma3:12b",
        "search.tool": "searxng",
        "search.iterations": 3,
    }

    if settings:
        default_settings.update(settings)

    # get_setting_from_db_main_thread has been removed from the codebase

    def get_db_session():
        return Mock()

    def get_settings_manager():
        mock_manager = Mock()
        mock_manager.get.side_effect = lambda k, d=None: default_settings.get(
            k, d
        )
        return mock_manager

    attributes = {
        # get_setting_from_db_main_thread has been removed
        "get_db_session": get_db_session,
        "get_settings_manager": get_settings_manager,
        # Add cache_clear methods for compatibility
        "get_db_session.cache_clear": lambda: None,
        "get_settings_manager.cache_clear": lambda: None,
    }

    mock_module = create_mock_module("db_utils", attributes)
    patch_module(
        monkeypatch, "src.local_deep_research.utilities.db_utils", mock_module
    )

    return mock_module
