import os
from typing import Any, Dict

from cachetools import LRUCache
from loguru import logger
from sqlalchemy import create_engine
from sqlalchemy.orm import Session, sessionmaker

from ..utilities.threading_utils import thread_specific_cache
from ..web.services.settings_manager import SettingsManager

# Database path.
DATA_DIR = os.path.abspath(
    os.path.join(os.path.dirname(__file__), "..", "..", "data")
)
DB_PATH = os.path.join(DATA_DIR, "ldr.db")


@thread_specific_cache(cache=LRUCache(maxsize=1))
def get_db_session() -> Session:
    """
    Returns:
        The singleton DB session.
    """
    engine = create_engine(f"sqlite:///{DB_PATH}")
    session_class = sessionmaker(bind=engine)
    return session_class()


@thread_specific_cache(cache=LRUCache(maxsize=1))
def get_settings_manager() -> SettingsManager:
    """
    Returns:
        The singleton settings manager.

    """
    return SettingsManager(db_session=get_db_session())


def get_db_setting(
    key: str, default_value: Any | None = None
) -> str | Dict[str, Any] | None:
    """
    Get a setting from the database with fallback to default value

    Args:
        key: The setting key.
        default_value: If the setting is not found, it will return this instead.

    Returns:
        The setting value.

    """
    try:
        # Get settings manager which handles database access
        value = get_settings_manager().get_setting(key)

        if value is not None:
            return value
    except Exception:
        logger.exception(f"Error getting setting {key} from database")

    logger.warning(f"Could not find setting '{key}' in the database.")
    return default_value
