"""Live end-to-end check of the LLM relevance filter against real arXiv results.

Hits arXiv for previews and a real Ollama endpoint for the judge, then runs
``filter_previews_for_relevance`` on the pair. Prints KEPT/REMOVED so a human
can eyeball whether the filter is doing the right thing for the chosen local
LLM and prompt.

Excluded from CI via the ``integration`` marker. Skips cleanly if Ollama is
unreachable so running the performance suite locally without a running
endpoint does not fail.

Environment variables (all optional — defaults target a typical local setup):

    LDR_TEST_OLLAMA_BASE_URL   Ollama endpoint (default http://localhost:11434)
    LDR_TEST_OLLAMA_MODEL      Model tag to load (default qwen3.5:9b)
    LDR_TEST_ARXIV_MAX         How many arXiv results to request (default 40)
"""

from __future__ import annotations

import os
from typing import Any, Dict, List
from urllib.parse import urlparse

import pytest
import requests

pytestmark = [
    pytest.mark.integration,
    pytest.mark.requires_llm,
    pytest.mark.slow,
]


DEFAULT_OLLAMA_URL = "http://localhost:11434"
DEFAULT_OLLAMA_MODEL = "qwen3.5:9b"


def _ollama_url() -> str:
    return os.environ.get("LDR_TEST_OLLAMA_BASE_URL", DEFAULT_OLLAMA_URL)


def _ollama_model() -> str:
    return os.environ.get("LDR_TEST_OLLAMA_MODEL", DEFAULT_OLLAMA_MODEL)


def _ollama_reachable(url: str, timeout: float = 2.0) -> bool:
    # Use safe_get with allow_private_ips=True — the reachability probe
    # targets a user-configured Ollama endpoint on a local/private
    # network, same pattern as the sibling eval scripts.
    from local_deep_research.security import safe_get

    try:
        resp = safe_get(
            f"{url.rstrip('/')}/api/tags",
            timeout=timeout,
            allow_private_ips=True,
        )
        return resp.status_code == 200
    except requests.RequestException:
        return False


@pytest.fixture(scope="module")
def ollama_llm():
    """Real ChatOllama bound to the configured endpoint, or skip the test."""
    url = _ollama_url()
    if not _ollama_reachable(url):
        pytest.skip(
            f"Ollama endpoint {url} not reachable. Set "
            "LDR_TEST_OLLAMA_BASE_URL to a running endpoint or run this "
            "test on a machine that can reach it."
        )

    # Import late so the module itself can be collected even if
    # langchain_ollama isn't installed (it is, via the main deps).
    from langchain_ollama import ChatOllama

    host = urlparse(url).netloc or url
    return ChatOllama(model=_ollama_model(), base_url=url, num_ctx=8192), host


def _arxiv_previews(query: str, max_results: int) -> List[Dict[str, Any]]:
    """Fetch arXiv previews in the dict shape the relevance filter expects.

    Uses the ``arxiv`` package directly (not ArXivSearchEngine) to avoid the
    rate-limiter, journal-reputation-filter, and thread-context machinery —
    we just want raw title+abstract pairs.
    """
    import arxiv

    client = arxiv.Client(page_size=max_results)
    search = arxiv.Search(
        query=query,
        max_results=max_results,
        sort_by=arxiv.SortCriterion.Relevance,
    )
    previews = []
    for paper in client.results(search):
        previews.append(
            {
                "title": paper.title.strip(),
                "snippet": (paper.summary or "").strip(),
                "url": paper.entry_id,
            }
        )
    return previews


# Queries chosen to exercise the keyword-bait failure mode. Each one has
# plausibly-matching noise on arXiv: papers that share tokens with the query
# but whose primary topic is something else.
_LIVE_QUERIES = [
    "LLM interpretability latest research",
    "sparse autoencoders for mechanistic interpretability",
]


@pytest.mark.parametrize("query", _LIVE_QUERIES, ids=lambda q: q.split()[0])
def test_relevance_filter_against_real_arxiv(ollama_llm, query, capsys):
    """Run arXiv → relevance filter → Ollama end-to-end and report decisions."""
    from local_deep_research.web_search_engines.relevance_filter import (
        filter_previews_for_relevance,
    )

    llm, host = ollama_llm
    max_results = int(os.environ.get("LDR_TEST_ARXIV_MAX", "40"))
    previews = _arxiv_previews(query, max_results)
    assert previews, "arXiv returned no results — check connectivity"

    with capsys.disabled():
        print(f"\n=== Query: {query!r} ===")
        print(f"    Judge: {_ollama_model()} @ {host}")
        print(f"    arXiv previews fetched: {len(previews)}")

    kept = filter_previews_for_relevance(
        llm=llm,
        previews=previews,
        query=query,
        max_filtered_results=None,  # let the judge decide
        engine_name="LiveArxivTest",
        batch_size=10,
        max_parallel_batches=4,
    )

    kept_titles = {p["title"] for p in kept}
    removed = [p for p in previews if p["title"] not in kept_titles]

    with capsys.disabled():
        print(f"    KEPT  ({len(kept)}):")
        for p in kept:
            print(f"      + {p['title'][:110]}")
        print(f"    REMOVED ({len(removed)}):")
        for p in removed[:25]:
            print(f"      - {p['title'][:110]}")
        if len(removed) > 25:
            print(f"      ... and {len(removed) - 25} more")

    # Soft sanity checks — the test exists primarily to surface output for
    # a human to read, but fail loudly if the filter collapses entirely.
    assert kept, (
        f"Filter rejected ALL {len(previews)} results for '{query}'. "
        "Either the judge is broken or the prompt over-rejects."
    )
    assert len(kept) < len(previews), (
        f"Filter kept ALL {len(previews)} results for '{query}'. "
        "The prompt is no longer filtering — likely broken."
    )
