"""Business flow tests: Knowledge Graph construction and querying.

Tests the flow:
  1. Ingest a document (which triggers graph building)
  2. Verify graph entities were created
  3. Search for entities in the graph
  4. Query entity neighborhood
  5. Find related documents through graph

Requires running Docker infra + Celery worker + LLM service.
"""

from __future__ import annotations

import asyncio
import json
import time
from pathlib import Path

import pytest
from httpx import AsyncClient

_INGEST_TIMEOUT = 180
_POLL_INTERVAL = 3


@pytest.mark.asyncio
class TestGraphBuildFlow:
    """End-to-end: Ingest → Graph Build → Graph Query."""

    async def _login(self, client: AsyncClient, api_prefix: str) -> str:
        resp = await client.post(f"{api_prefix}/mock/login", json={
            "username": "admin",
            "password": "admin123",
        })
        return resp.json()["access_token"]

    async def _wait_ingest(self, client: AsyncClient, api_prefix: str, task_id: str, headers: dict) -> dict:
        start = time.time()
        while time.time() - start < _INGEST_TIMEOUT:
            resp = await client.get(f"{api_prefix}/ingest/status/{task_id}", headers=headers)
            body = resp.json()
            if body.get("status") in ("COMPLETED", "FAILED"):
                return body
            await asyncio.sleep(_POLL_INTERVAL)
        pytest.fail("Ingest timeout")

    async def test_ingest_builds_graph(
        self,
        client: AsyncClient,
        api_prefix: str,
        example_pdf_path: Path,
    ):
        """After ingesting a document, graph entities should be created."""
        token = await self._login(client, api_prefix)
        headers = {"Authorization": f"Bearer {token}"}

        doc_id = f"graph-test-{int(time.time())}"

        # Ingest
        meta = json.dumps({
            "doc_id": doc_id,
            "title": "知识图谱构建测试文档",
            "issuing_org": "广东省人民政府",
            "doc_type": "通知",
            "acl_ids": ["A_01"],
        })
        with open(example_pdf_path, "rb") as f:
            resp = await client.post(
                f"{api_prefix}/ingest/webhook/document",
                data={"metadata": meta},
                files={"file": (example_pdf_path.name, f, "application/pdf")},
            )
        assert resp.status_code == 200
        task_id = resp.json()["task_id"]

        result = await self._wait_ingest(client, api_prefix, task_id, headers)
        assert result["status"] == "COMPLETED"

        # Check document graph sub-graph
        resp = await client.get(
            f"{api_prefix}/document/{doc_id}/graph",
            headers=headers,
        )
        assert resp.status_code == 200
        graph_data = resp.json()
        # Graph should contain nodes and edges (if LLM extracted entities)
        assert "nodes" in graph_data or isinstance(graph_data, dict)

        # Check global graph overview
        resp = await client.get(
            f"{api_prefix}/graph/overview",
            headers=headers,
        )
        assert resp.status_code == 200

        # Search for entities related to the ingested doc's issuing org
        resp = await client.post(
            f"{api_prefix}/graph/search",
            json={"name": "广东"},
            headers=headers,
        )
        assert resp.status_code == 200

        # Clean up
        await client.delete(
            f"{api_prefix}/admin/document/{doc_id}",
            headers=headers,
        )
