from __future__ import annotations

import pytest


@pytest.mark.integration
def test_search_returns_non_empty_groups(client):
    response = client.post(
        "/api/v1/search/",
        json={
            "repo_id": "ad/adpilot-indexing-commit-intel.com",
            "question": "How does commit analysis get triggered?",
            "snapshot_id": "snap_demo",
        },
    )
    assert response.status_code == 200
    body = response.json()
    assert body["code_snippets"]
    assert body["doc_excerpts"]
    assert body["intent"]["type"] in {"code_lookup", "architecture", "mixed"}


@pytest.mark.integration
def test_query_returns_answer_with_citations(client):
    response = client.post(
        "/api/v1/query/",
        json={
            "repo_id": "ad/adpilot-indexing-commit-intel.com",
            "question": "How does commit analysis get triggered?",
            "snapshot_id": "snap_demo",
        },
    )
    assert response.status_code == 200
    body = response.json()
    assert body["answer"]
    assert len(body["citations"]) >= 1
    assert body["code_snippets"] or body["doc_excerpts"]
    assert body["reasoning"] == []
    assert body["metadata"]["intent_type"]
    assert "retrieval_fallback_used" in body["metadata"]


@pytest.mark.integration
def test_query_include_reasoning_returns_structured_trace(client, monkeypatch):
    from app.generation.llm_client import LLMClient
    from app.api.routes import query as query_route

    async def fake_complete_json(messages, model=None):
        return {
            "answer": "Commit analysis is triggered via graph.delta.ready events [1].",
            "reasoning": [
                {
                    "step": 1,
                    "description": "Used the primary code snippet about the trigger",
                    "used_indices": [1, 99],
                }
            ],
            "used_indices": [1, 99],
        }

    async def fake_complete(messages, model=None):
        raise AssertionError("plain complete should not be used when include_reasoning")

    llm = LLMClient(client=object())  # type: ignore[arg-type]
    llm.complete_json = fake_complete_json  # type: ignore[method-assign]
    llm.complete = fake_complete  # type: ignore[method-assign]
    monkeypatch.setattr(query_route._query_service, "_llm_client", llm)

    response = client.post(
        "/api/v1/query/",
        json={
            "repo_id": "ad/adpilot-indexing-commit-intel.com",
            "question": "How does commit analysis get triggered?",
            "snapshot_id": "snap_demo",
            "options": {"include_reasoning": True},
        },
    )
    assert response.status_code == 200
    body = response.json()
    assert body["answer"]
    assert body["reasoning"]
    assert body["reasoning"][0]["step"] == 1
    assert 99 not in body["reasoning"][0]["used_indices"]
    assert all(c["index"] != 99 for c in body["citations"])
    assert body["metadata"]["intent_type"]
    assert "retrieval_fallback_used" in body["metadata"]
    assert body["metadata"].get("answer_mode") == "rag"
