"""Gestão de strings de busca: geral (base) e por base de dados."""

from django.db.models import Count

from reviews.models import Article, SearchSession
from rsl.services.search_string import generate_search_string


def get_or_create_session(review_id: int, source_id: int | None = None) -> SearchSession:
    session = SearchSession.objects.filter(review_id=review_id, source_id=source_id).first()
    if not session:
        session = SearchSession(review_id=review_id, source_id=source_id, search_string="")
        session.save()
        
    return session


def ensure_all_sessions(review) -> None:
    """Garante sessão base + uma por fonte vinculada à revisão."""
    get_or_create_session(review.id, source_id=None)
    for source in review.sources.all():
        get_or_create_session(review.id, source_id=source.id)
    


def save_base_string(review, text: str) -> SearchSession:
    session = get_or_create_session(review.id, source_id=None)
    session.search_string = text or ""
    
    return session


def save_source_string(review, source_id: int, text: str) -> SearchSession | None:
    linked_ids = set(review.sources.values_list("id", flat=True))
    if source_id not in linked_ids:
        return None
    session = get_or_create_session(review.id, source_id=source_id)
    session.search_string = text or ""
    
    return session


def copy_base_to_sources(review, source_ids: list[int] | None = None) -> int:
    base = review.get_base_search_session()
    if not base or not base.search_string.strip():
        return 0
    targets = list(review.sources.all())
    if source_ids:
        targets = [s for s in targets if s.id in source_ids]
    count = 0
    for source in targets:
        session = get_or_create_session(review.id, source_id=source.id)
        session.search_string = base.search_string
        count += 1
    
    return count


def generate_and_save_base(review) -> str:
    text = generate_search_string(review)
    save_base_string(review, text)
    return text


def articles_count_by_source(review_id: int) -> dict[int, int]:
    counts: dict[int, int] = {}
    for row in (
        Article.objects.filter(review_id=review_id, source_id__isnull=False)
        .values("source_id")
        .annotate(c=Count("id"))
    ):
        counts[row["source_id"]] = row["c"]
    return counts


def get_search_overview(review) -> dict:
    """Resumo para UI: string geral + lista por fonte."""
    ensure_all_sessions(review)
    base = review.get_base_search_session()
    article_counts = articles_count_by_source(review.id)
    sources_data = []
    for source in review.sources.order_by("name"):
        sess = SearchSession.objects.filter(review_id=review.id, source_id=source.id).first()
        sources_data.append(
            {
                "source": source,
                "session": sess,
                "search_string": (sess.search_string if sess else "") or "",
                "has_string": bool(sess and sess.search_string.strip()),
                "article_count": article_counts.get(source.id, 0),
            }
        )
    configured = sum(1 for s in sources_data if s["has_string"])
    total_sources = len(sources_data)
    return {
        "base_session": base,
        "base_string": (base.search_string if base else "") or "",
        "has_base": bool(base and base.search_string.strip()),
        "sources": sources_data,
        "configured_sources": configured,
        "total_sources": total_sources,
        "all_sources_configured": total_sources > 0 and configured == total_sources,
    }


def review_search_strings_complete(review) -> bool:
    overview = get_search_overview(review)
    if not overview["has_base"]:
        return False
    if overview["total_sources"] == 0:
        return True
    return overview["all_sources_configured"]
