"""Shared thread-local storage for settings context

This module provides a single thread-local storage instance that can be
shared across different modules to maintain settings context in threads.
"""

import os
import threading

from ..settings.manager import get_typed_setting_value


class NoSettingsContextError(Exception):
    """Raised when settings context is not available in a thread."""

    pass


# Shared thread-local storage for settings context
_thread_local = threading.local()


def set_settings_context(settings_context):
    """Set a settings context for the current thread."""
    _thread_local.settings_context = settings_context


def get_settings_context():
    """Get the settings context for the current thread."""
    if hasattr(_thread_local, "settings_context"):
        return _thread_local.settings_context
    return None


def get_setting_from_snapshot(
    key,
    default=None,
    username=None,
    settings_snapshot=None,
    check_fallback_llm=False,
):
    """Get setting from context only - no database access from threads.

    Args:
        key: Setting key to retrieve
        default: Default value if setting not found
        username: Username (unused, kept for backward compatibility)
        settings_snapshot: Optional settings snapshot dict
        check_fallback_llm: Whether to check LDR_USE_FALLBACK_LLM env var

    Returns:
        Setting value or default

    Raises:
        RuntimeError: If no settings context is available
    """
    # First check if we have settings_snapshot passed directly
    value = None
    if settings_snapshot and key in settings_snapshot:
        value = settings_snapshot[key]
        # Handle both full format {"value": x} and simplified format (just x)
        if isinstance(value, dict) and "value" in value:
            value = get_typed_setting_value(
                key,
                value["value"],
                value.get("ui_element", "text"),
            )
        # else: value is already the raw value from simplified snapshot
    # Search for child keys.
    elif settings_snapshot:
        for k, v in settings_snapshot.items():
            if k.startswith(f"{key}."):
                k = k.removeprefix(f"{key}.")
                # Handle both full format {"value": x} and simplified format (just x)
                if isinstance(v, dict) and "value" in v:
                    v = get_typed_setting_value(
                        key, v["value"], v.get("ui_element", "text")
                    )
                # else: v is already the raw value from simplified snapshot
                if value is None:
                    value = {k: v}
                else:
                    value[k] = v

    if value is not None:
        # Extract value from dict structure if needed
        return value

    # Check if we have a settings context in this thread
    if (
        hasattr(_thread_local, "settings_context")
        and _thread_local.settings_context
    ):
        value = _thread_local.settings_context.get_setting(key, default)
        # Extract value from dict structure if needed (same as above)
        if isinstance(value, dict) and "value" in value:
            return value["value"]
        return value

    # In CI/test environment with fallback LLM, return default values
    # But skip this if we're in test mode with mocks
    if (
        check_fallback_llm
        and os.environ.get("LDR_USE_FALLBACK_LLM", "")
        and not os.environ.get("LDR_TESTING_WITH_MOCKS", "")
    ):
        from loguru import logger

        logger.debug(
            f"Using default value for {key} in fallback LLM environment"
        )
        return default

    # If a default was provided, return it instead of raising an exception
    if default is not None:
        from loguru import logger

        logger.debug(
            f"Setting {key} not found in snapshot or context, using default: {default}"
        )
        return default

    # Only raise the exception if no default was provided
    raise NoSettingsContextError(
        f"No settings context available in thread for key '{key}'. All settings must be passed via settings_snapshot."
    )
