"""Progresso e pré-requisitos do fluxo SLR."""

from dataclasses import dataclass

from django.urls import reverse

from reviews.models import Article, DataExtractionField, SearchSession


@dataclass
class PhaseStep:
    key: str
    label: str
    done: bool
    detail: str
    url_endpoint: str | None = None
    url_anchor: str = ""
    blocked: bool = False
    block_reason: str = ""


def review_has_sources(review) -> bool:
    return review.sources.count() > 0


def review_has_protocol(review) -> bool:
    return bool(
        review.objective.strip()
        or review.population.strip()
        or review.questions.exists()
        or review.selection_criteria.exists()
    )


def review_has_search_string(review) -> bool:
    from rsl.services.search_sessions import review_search_strings_complete

    return review_search_strings_complete(review)


def review_has_per_source_strings(review) -> bool:
    from rsl.services.search_sessions import get_search_overview

    overview = get_search_overview(review)
    return overview["total_sources"] > 0 and overview["all_sources_configured"]


def review_has_articles(review) -> bool:
    return Article.objects.filter(review_id=review.id).count() > 0


def review_has_screened(review) -> bool:
    total = Article.objects.filter(review_id=review.id).count()
    unclassified = Article.objects.filter(review_id=review.id, status="U").count()
    return total > 0 and unclassified < total


def review_has_accepted(review) -> bool:
    return Article.objects.filter(review_id=review.id, status="A").count() > 0


def review_has_extraction_form(review) -> bool:
    return review.extraction_fields.exists()


def get_planning_steps(review) -> list[PhaseStep]:
    return [
        PhaseStep(
            "sources",
            "Bases de dados",
            review_has_sources(review),
            f"{review.sources.count()} base(s) selecionada(s)",
            "planning.protocol",
            url_anchor="bases",
        ),
        PhaseStep(
            "protocol",
            "Protocolo (PICOC)",
            review_has_protocol(review),
            "Objetivo, PICOC, critérios ou perguntas",
            "planning.protocol",
        ),
        PhaseStep(
            "search",
            "String de busca (geral)",
            bool(review.get_base_search_session() and review.get_base_search_session().search_string.strip()),
            "String geral no protocolo",
            "planning.protocol",
        ),
        PhaseStep(
            "search_per_source",
            "Strings por base de dados",
            review_has_per_source_strings(review),
            "Uma string por fonte configurada",
            "planning.protocol",
            url_anchor="strings",
        ),
        PhaseStep(
            "quality_design",
            "Checklist de qualidade",
            review.quality_questions.exists(),
            f"{review.quality_questions.count()} pergunta(s)",
            "planning.quality",
        ),
        PhaseStep(
            "extraction_design",
            "Formulário de extração",
            review_has_extraction_form(review),
            f"{review.extraction_fields.count()} campo(s)",
            "planning.extraction",
        ),
    ]


def get_conducting_steps(review) -> list[PhaseStep]:
    planning_ok = review_has_sources(review) and review_has_protocol(review)
    steps = [
        PhaseStep(
            "search",
            "Strings por base de dados",
            planning_ok and _has_source_sessions(review),
            "String definida em cada base",
            "planning.protocol",
            url_anchor="strings",
            blocked=not planning_ok,
            block_reason="Configure bases e protocolo no Planejamento.",
        ),
        PhaseStep(
            "import",
            "Importação",
            review_has_articles(review),
            f"{Article.objects.filter(review_id=review.id).count()} artigo(s)",
            "conducting.import_studies",
            blocked=not review_has_sources(review),
            block_reason="Selecione bases no Protocolo (passo 1).",
        ),
        PhaseStep(
            "selection",
            "Seleção de estudos",
            review_has_screened(review),
            "Triagem iniciada",
            "conducting.selection",
            blocked=not review_has_articles(review),
            block_reason="Importe estudos antes da seleção.",
        ),
        PhaseStep(
            "qa",
            "Avaliação de qualidade",
            review_has_accepted(review) and review.quality_questions.exists(),
            "Artigos aceitos avaliados",
            "conducting.quality_assessment",
            blocked=not review_has_accepted(review),
            block_reason="Aceite artigos na seleção primeiro.",
        ),
        PhaseStep(
            "extraction",
            "Extração de dados",
            bool(review.get_final_selection_articles()) and review_has_extraction_form(review),
            "Seleção final com formulário",
            "conducting.data_extraction",
            blocked=not review_has_extraction_form(review),
            block_reason="Defina campos de extração no planejamento.",
        ),
        PhaseStep(
            "analysis",
            "Análise",
            review_has_articles(review),
            "Gráficos e resumo",
            "conducting.analysis",
            blocked=not review_has_articles(review),
            block_reason="Importe artigos para analisar.",
        ),
    ]
    return steps


def _has_source_sessions(review) -> bool:
    return review_has_per_source_strings(review)


def planning_progress(review) -> int:
    steps = get_planning_steps(review)
    if not steps:
        return 0
    return int(100 * sum(1 for s in steps if s.done) / len(steps))


def conducting_progress(review) -> int:
    steps = get_conducting_steps(review)
    if not steps:
        return 0
    return int(100 * sum(1 for s in steps if s.done) / len(steps))


def _step_url(url_endpoint: str | None, review_id: int, anchor: str = "") -> str | None:
    if not url_endpoint:
        return None
    django_name = url_endpoint.replace(".", ":", 1)
    url = reverse(django_name, kwargs={"review_id": review_id})
    if anchor:
        url += f"#{anchor}"
    return url


def steps_for_template(steps, review_id: int):
    return [
        {
            "key": s.key,
            "label": s.label,
            "done": s.done,
            "detail": s.detail,
            "blocked": s.blocked,
            "block_reason": s.block_reason,
            "url": _step_url(s.url_endpoint, review_id, s.url_anchor),
        }
        for s in steps
    ]


def screening_funnel(review) -> dict:
    """Contagens para diagrama PRISMA simplificado."""
    q = Article.objects.filter(review_id=review.id)
    total = q.count()
    accepted = q.filter(status="A").count()
    rejected = q.filter(status="R").count()
    duplicated = q.filter(status="D").count()
    unclassified = q.filter(status="U").count()
    final = len(review.get_final_selection_articles())
    return {
        "identificados": total,
        "nao_classificados": unclassified,
        "aceitos": accepted,
        "rejeitados": rejected,
        "duplicados": duplicated,
        "selecao_final": final,
    }
