from typing import Any, Dict, Optional, Union

from loguru import logger

from ...database.models import Setting
from ...utilities.db_utils import get_settings_manager


def set_setting(
    key: str, value: Any, commit: bool = True, db_session=None
) -> bool:
    """
    Set a setting value

    Args:
        key: Setting key
        value: Setting value
        commit: Whether to commit the change
        db_session: Optional database session

    Returns:
        bool: True if successful
    """
    manager = get_settings_manager(db_session)
    return bool(manager.set_setting(key, value, commit))


def get_all_settings() -> Dict[str, Any]:
    """
    Get all settings, optionally filtered by type

    Returns:
        Dict[str, Any]: Dictionary of settings

    """
    manager = get_settings_manager()
    return manager.get_all_settings()  # type: ignore[no-any-return]


def create_or_update_setting(
    setting: Union[Dict[str, Any], Setting],
    commit: bool = True,
    db_session=None,
) -> Optional[Setting]:
    """
    Create or update a setting

    Args:
        setting: Setting dictionary or object
        commit: Whether to commit the change
        db_session: Optional database session

    Returns:
        Optional[Setting]: The setting object if successful
    """
    manager = get_settings_manager(db_session)
    return manager.create_or_update_setting(setting, commit)  # type: ignore[no-any-return]


def invalidate_settings_caches(username=None):
    """Invalidate all settings-related caches after a settings mutation.

    Call this after any route that creates, updates, or deletes settings
    so background services pick up changes immediately.

    Safe to call from anywhere — silently skips caches that aren't initialized.

    Args:
        username: If provided, invalidates only that user's scheduler cache.
                  If None, invalidates all users' scheduler caches.
    """
    # 1. News scheduler per-user settings cache (TTLCache, 5-min TTL)
    try:
        from ...news.subscription_manager.scheduler import get_news_scheduler

        scheduler = get_news_scheduler()
        if username is not None:
            scheduler.invalidate_user_settings_cache(username)
        else:
            scheduler.invalidate_all_settings_cache()
    except Exception:
        logger.debug("Could not invalidate scheduler cache", exc_info=True)

    # 2. LLM provider cache (functools.cache, no TTL)
    try:
        from ...config.llm_config import get_available_providers

        get_available_providers.cache_clear()
    except Exception:
        logger.debug("Could not clear provider cache", exc_info=True)


def validate_setting(
    setting: Setting, value: Any
) -> tuple[bool, Optional[str]]:
    """
    Validate a setting value based on its type and constraints

    Args:
        setting: The Setting object to validate against
        value: The value to validate

    Returns:
        tuple[bool, Optional[str]]: (is_valid, error_message)
    """
    from ..routes.settings_routes import (
        validate_setting as routes_validate_setting,
    )

    return routes_validate_setting(setting, value)
