"""
RAG Service Factory

Provides get_rag_service() for creating LibraryRAGService instances
with appropriate settings. Extracted from rag_routes.py to avoid
circular imports (service → routes).
"""

import json
from typing import Optional

from loguru import logger

from ...database.models.library import Collection
from ...database.session_context import get_user_db_session
from ...utilities.db_utils import get_settings_manager
from ...utilities.type_utils import to_bool
from ..services.library_rag_service import LibraryRAGService


def get_rag_service(
    username: str,
    collection_id: Optional[str] = None,
    use_defaults: bool = False,
    db_password: Optional[str] = None,
) -> LibraryRAGService:
    """
    Get RAG service instance with appropriate settings.

    Args:
        username: Username for database access and settings lookup
        collection_id: Optional collection UUID to load stored settings from
        use_defaults: When True, ignore stored collection settings and use
            current defaults. Pass True on force-reindex so that the new
            default embedding model is picked up.
        db_password: Optional database password for encrypted databases

    If collection_id is provided:
    - Uses collection's stored settings if they exist (unless use_defaults=True)
    - Uses current defaults for new collections (and stores them)

    If no collection_id:
    - Uses current default settings
    """
    settings = get_settings_manager(username=username)

    # Get current default settings.
    # The local_search_* keys are written by the embedding-settings page and
    # have no JSON defaults file yet, so explicit fallbacks are required to
    # avoid TypeError / None propagation on fresh installs.
    default_embedding_model = (
        settings.get_setting("local_search_embedding_model")
        or "all-MiniLM-L6-v2"
    )
    default_embedding_provider = (
        settings.get_setting("local_search_embedding_provider")
        or "sentence_transformers"
    )
    default_chunk_size = int(
        settings.get_setting("local_search_chunk_size") or 1000
    )
    default_chunk_overlap = int(
        settings.get_setting("local_search_chunk_overlap") or 200
    )
    default_splitter_type = (
        settings.get_setting("local_search_splitter_type") or "recursive"
    )
    default_text_separators = settings.get_setting(
        "local_search_text_separators"
    )
    # Parse JSON string to list
    if isinstance(default_text_separators, str):
        try:
            default_text_separators = json.loads(default_text_separators)
        except json.JSONDecodeError:
            logger.warning(
                "Invalid JSON for local_search_text_separators: %r — "
                "using default separators",
                default_text_separators,
            )
            default_text_separators = ["\n\n", "\n", ". ", " ", ""]
    elif default_text_separators is None:
        default_text_separators = ["\n\n", "\n", ". ", " ", ""]
    default_distance_metric = (
        settings.get_setting("local_search_distance_metric") or "cosine"
    )
    default_normalize_vectors = settings.get_bool_setting(
        "local_search_normalize_vectors"
    )
    default_index_type = (
        settings.get_setting("local_search_index_type") or "Flat"
    )

    # If collection_id provided, check for stored settings
    if collection_id:
        with get_user_db_session(username, db_password) as db_session:
            collection = (
                db_session.query(Collection).filter_by(id=collection_id).first()
            )

            if collection and collection.embedding_model and not use_defaults:
                # Use collection's stored settings
                logger.info(
                    f"Using stored settings for collection {collection_id}: "
                    f"{collection.embedding_model_type.value if collection.embedding_model_type else 'unknown'}/{collection.embedding_model}"
                )
                # Handle normalize_vectors - may be stored as string in some cases
                coll_normalize = collection.normalize_vectors
                if coll_normalize is not None:
                    coll_normalize = to_bool(coll_normalize)
                else:
                    coll_normalize = default_normalize_vectors

                def _col(stored, default):
                    """Use stored collection value if not None, else default."""
                    return stored if stored is not None else default

                return LibraryRAGService(
                    username=username,
                    embedding_model=collection.embedding_model,
                    embedding_provider=collection.embedding_model_type.value
                    if collection.embedding_model_type
                    else default_embedding_provider,
                    chunk_size=_col(collection.chunk_size, default_chunk_size),
                    chunk_overlap=_col(
                        collection.chunk_overlap, default_chunk_overlap
                    ),
                    splitter_type=_col(
                        collection.splitter_type, default_splitter_type
                    ),
                    text_separators=_col(
                        collection.text_separators, default_text_separators
                    ),
                    distance_metric=_col(
                        collection.distance_metric, default_distance_metric
                    ),
                    normalize_vectors=coll_normalize,
                    index_type=_col(collection.index_type, default_index_type),
                    db_password=db_password,
                )
            if collection:
                # New collection - use defaults and store them
                logger.info(
                    f"New collection {collection_id}, using and storing default settings"
                )

                # Create service with defaults
                return LibraryRAGService(
                    username=username,
                    embedding_model=default_embedding_model,
                    embedding_provider=default_embedding_provider,
                    chunk_size=default_chunk_size,
                    chunk_overlap=default_chunk_overlap,
                    splitter_type=default_splitter_type,
                    text_separators=default_text_separators,
                    distance_metric=default_distance_metric,
                    normalize_vectors=default_normalize_vectors,
                    index_type=default_index_type,
                    db_password=db_password,
                )

                # Store settings on collection (will be done during indexing)
                # Note: We don't store here because we don't have embedding_dimension yet
                # It will be stored in index_collection when first document is indexed

    # No collection or fallback - use current defaults
    return LibraryRAGService(
        username=username,
        embedding_model=default_embedding_model,
        embedding_provider=default_embedding_provider,
        chunk_size=default_chunk_size,
        chunk_overlap=default_chunk_overlap,
        splitter_type=default_splitter_type,
        text_separators=default_text_separators,
        distance_metric=default_distance_metric,
        normalize_vectors=default_normalize_vectors,
        index_type=default_index_type,
        db_password=db_password,
    )
