from __future__ import annotations

import json
import re

import pytest


def _parse_sse_events(text: str) -> list[tuple[str, dict]]:
    events: list[tuple[str, dict]] = []
    for block in re.split(r"\n\n+", text.strip()):
        if not block:
            continue
        event_type = "message"
        data_line = None
        for line in block.splitlines():
            if line.startswith("event: "):
                event_type = line.removeprefix("event: ").strip()
            elif line.startswith("data: "):
                data_line = line.removeprefix("data: ").strip()
        if data_line is not None:
            events.append((event_type, json.loads(data_line)))
    return events


@pytest.mark.acceptance
@pytest.mark.integration
def test_q1_commit_analysis_trigger(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["intent"]["type"] in {"code_lookup", "architecture", "mixed"}
    assert body["code_snippets"]
    assert body["doc_excerpts"]


@pytest.mark.acceptance
@pytest.mark.integration
def test_q2_redis_consumer_refactor(client):
    response = client.post(
        "/api/v1/search/",
        json={
            "repo_id": "ad/adpilot-indexing-commit-intel.com",
            "question": "Why was the Redis consumer refactored?",
            "snapshot_id": "snap_demo",
        },
    )
    assert response.status_code == 200
    body = response.json()
    assert body["intent"]["type"] in {"historical", "mixed", "general"}
    assert body["related_commits"]


@pytest.mark.acceptance
@pytest.mark.integration
def test_q3_repo_sync_port(client):
    response = client.post(
        "/api/v1/search/",
        json={
            "repo_id": "ad/adpilot-indexing-commit-intel.com",
            "question": "What port does repo sync use?",
            "snapshot_id": "snap_demo",
        },
    )
    assert response.status_code == 200
    body = response.json()
    assert body["intent"]["type"] in {"documentation", "general", "mixed"}
    assert body["doc_excerpts"]
    assert not body["code_snippets"] or len(body["doc_excerpts"]) >= len(body["code_snippets"])


@pytest.mark.acceptance
@pytest.mark.integration
def test_q4_process_delta_definition(client):
    response = client.post(
        "/api/v1/search/",
        json={
            "repo_id": "ad/adpilot-indexing-commit-intel.com",
            "question": "Where is ProcessDelta defined?",
            "snapshot_id": "snap_demo",
        },
    )
    assert response.status_code == 200
    body = response.json()
    assert body["code_snippets"]
    snippet = body["code_snippets"][0]
    assert snippet["file_path"]
    assert snippet["symbol_name"] == "ProcessDelta"
    assert snippet["start_line"] is not None
    assert snippet["end_line"] is not None


@pytest.mark.acceptance
@pytest.mark.integration
def test_q5_indexing_pipeline_query(client):
    response = client.post(
        "/api/v1/query/",
        json={
            "repo_id": "ad/adpilot-indexing-commit-intel.com",
            "question": "Explain the indexing pipeline end to end",
            "snapshot_id": "snap_demo",
        },
    )
    assert response.status_code == 200
    body = response.json()
    assert body["answer"]
    source_count = (
        len(body.get("code_snippets", []))
        + len(body.get("doc_excerpts", []))
        + len(body.get("related_commits", []))
    )
    assert source_count >= 2 or len(body.get("citations", [])) >= 2


@pytest.mark.acceptance
@pytest.mark.integration
def test_q5_indexing_pipeline_sse(client):
    response = client.post(
        "/api/v1/query/",
        json={
            "repo_id": "ad/adpilot-indexing-commit-intel.com",
            "question": "Explain the indexing pipeline end to end",
            "snapshot_id": "snap_demo",
            "options": {"stream": True},
        },
    )
    assert response.status_code == 200
    events = _parse_sse_events(response.text)
    assert events[0][0] == "start"
    assert events[-1][0] == "done"
    assert any(name == "token" for name, _ in events)
