"""Tests for Google Patents client — httpx MockTransport ile."""

from __future__ import annotations

import asyncio
import time

import httpx
import pytest

from app.services.prior_art import GooglePatentsClient, GooglePatentsError

_GOOGLE_RESPONSE: dict = {
    "results": {
        "cluster": [
            {
                "result": [
                    {
                        "patent": {
                            "publication_number": "US9876543B2",
                            "title": "Hybrid post-quantum key exchange",
                            "snippet": "A method for establishing a shared secret using ML-DSA and X25519...",
                            "priority_date": "2019-03-15",
                            "publication_date": "2021-05-20",
                            "assignee": "Example Corp.",
                            "inventor": ["Alice Smith", "Bob Jones"],
                        },
                    },
                    {
                        "patent": {
                            "publication_number": "CN202100001A",
                            "title": "量子安全通信网关",
                            "snippet": "量子安全通信网关...",
                            "priority_date": "2020-01-10",
                            "publication_date": "2022-07-15",
                            "assignee": ["Huawei Tech Co."],
                            "inventor": "Zhang Wei",
                        },
                    },
                    {
                        # Geçersiz — publication_number yok, parser atlar
                        "patent": {"title": "Missing pub number"},
                    },
                ],
            },
        ],
    },
}


def _make_client(handler, *, min_interval: float = 0.0) -> GooglePatentsClient:
    transport = httpx.MockTransport(handler)
    http = httpx.AsyncClient(
        transport=transport,
        timeout=5.0,
        headers={"User-Agent": "test"},
    )
    return GooglePatentsClient(http_client=http, min_interval_seconds=min_interval)


@pytest.mark.asyncio
async def test_search_parses_results_correctly() -> None:
    def handler(request: httpx.Request) -> httpx.Response:
        assert "patents.google.com" in str(request.url)
        return httpx.Response(200, json=_GOOGLE_RESPONSE)

    client = _make_client(handler)
    try:
        hits = await client.search("post-quantum gateway", limit=5)
    finally:
        await client.close()

    # 3 patent entry var ama biri pub_no'sız — 2 hit dönmeli
    assert len(hits) == 2

    us = hits[0]
    assert us.source == "google"
    assert us.patent_no == "US9876543B2"
    assert us.title == "Hybrid post-quantum key exchange"
    assert us.abstract and "ML-DSA" in us.abstract
    assert us.applicant == "Example Corp."
    assert us.inventors == ["Alice Smith", "Bob Jones"]
    assert us.filing_date == "2019-03-15"
    assert us.publication_date == "2021-05-20"
    assert us.url == "https://patents.google.com/patent/US9876543B2"

    cn = hits[1]
    assert cn.patent_no == "CN202100001A"
    assert cn.applicant == "Huawei Tech Co."  # list → first
    assert cn.inventors == ["Zhang Wei"]  # string → list


@pytest.mark.asyncio
async def test_search_respects_limit() -> None:
    def handler(request: httpx.Request) -> httpx.Response:
        return httpx.Response(200, json=_GOOGLE_RESPONSE)

    client = _make_client(handler)
    try:
        hits = await client.search("q", limit=1)
    finally:
        await client.close()
    assert len(hits) == 1


@pytest.mark.asyncio
async def test_search_http_error_raises() -> None:
    def handler(request: httpx.Request) -> httpx.Response:
        return httpx.Response(503, text="Service unavailable")

    client = _make_client(handler)
    try:
        with pytest.raises(GooglePatentsError) as exc:
            await client.search("anything")
    finally:
        await client.close()
    assert "503" in str(exc.value)


@pytest.mark.asyncio
async def test_search_invalid_json_raises() -> None:
    def handler(request: httpx.Request) -> httpx.Response:
        return httpx.Response(200, text="<html>not json</html>")

    client = _make_client(handler)
    try:
        with pytest.raises(GooglePatentsError):
            await client.search("anything")
    finally:
        await client.close()


@pytest.mark.asyncio
async def test_empty_results_returns_empty_list() -> None:
    def handler(request: httpx.Request) -> httpx.Response:
        return httpx.Response(200, json={"results": {"cluster": []}})

    client = _make_client(handler)
    try:
        hits = await client.search("zzz-no-match")
    finally:
        await client.close()
    assert hits == []


@pytest.mark.asyncio
async def test_rate_limit_waits_between_calls() -> None:
    """min_interval_seconds kadar bekler."""
    call_times: list[float] = []

    def handler(request: httpx.Request) -> httpx.Response:
        call_times.append(time.monotonic())
        return httpx.Response(200, json={"results": {"cluster": []}})

    client = _make_client(handler, min_interval=0.3)
    try:
        await client.search("a")
        await client.search("b")
    finally:
        await client.close()

    assert len(call_times) == 2
    gap = call_times[1] - call_times[0]
    assert gap >= 0.25, f"rate limit respected ({gap:.3f}s, beklenen ≥0.25s)"


@pytest.mark.asyncio
async def test_concurrent_searches_serialize_via_lock() -> None:
    """Aynı anda iki arama — lock serialize etmeli, min_interval uygulamalı."""
    order: list[str] = []

    async def handler_async():
        order.append("start")
        await asyncio.sleep(0.01)
        order.append("end")

    def handler(request: httpx.Request) -> httpx.Response:
        # MockTransport sync; tracking için basit
        order.append(str(request.url)[-1])
        return httpx.Response(200, json={"results": {"cluster": []}})

    client = _make_client(handler, min_interval=0.2)
    try:
        await asyncio.gather(client.search("a"), client.search("b"))
    finally:
        await client.close()

    assert len(order) == 2
