"""Tests for the FastAPI REST API (api.py)."""

from __future__ import annotations

import pytest
from httpx import AsyncClient, ASGITransport

from review_mcp import db
from review_mcp.api import app


@pytest.fixture
async def client(tmp_db):
    """Async httpx client hitting the FastAPI app."""
    await db.init_db()
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as c:
        yield c


# --------------- GET summary ---------------


async def test_summary_empty(client):
    resp = await client.get("/api/reviews/summary")
    assert resp.status_code == 200
    assert resp.json() == []


async def test_summary_with_data(client):
    await client.post("/api/reviews/page-a", json={"author": "a", "text": "t1"})
    await client.post("/api/reviews/page-a", json={"author": "a", "text": "t2"})
    await client.post("/api/reviews/page-b", json={"author": "b", "text": "t3"})

    resp = await client.get("/api/reviews/summary")
    data = resp.json()
    assert len(data) == 2
    pa = next(d for d in data if d["page_id"] == "page-a")
    assert pa["open"] == 2
    assert pa["total"] == 2


# --------------- GET reviews ---------------


async def test_get_all_reviews(client):
    await client.post("/api/reviews/p1", json={"author": "a", "text": "t1"})
    await client.post("/api/reviews/p2", json={"author": "b", "text": "t2"})

    resp = await client.get("/api/reviews")
    assert resp.status_code == 200
    assert len(resp.json()) == 2


async def test_get_reviews_by_page(client):
    await client.post("/api/reviews/p1", json={"author": "a", "text": "t1"})
    await client.post("/api/reviews/p2", json={"author": "b", "text": "t2"})

    resp = await client.get("/api/reviews/p1")
    data = resp.json()
    assert len(data) == 1
    assert data[0]["page_id"] == "p1"


async def test_get_reviews_empty_page(client):
    resp = await client.get("/api/reviews/nonexistent")
    assert resp.status_code == 200
    assert resp.json() == []


# --------------- POST review ---------------


async def test_create_review(client):
    resp = await client.post(
        "/api/reviews/my-page",
        json={"author": "tester", "text": "Looks good"},
    )
    assert resp.status_code == 201
    data = resp.json()
    assert data["page_id"] == "my-page"
    assert data["author"] == "tester"
    assert data["text"] == "Looks good"
    assert data["status"] == "open"
    assert data["id"] >= 1


async def test_create_review_default_author(client):
    resp = await client.post("/api/reviews/pg", json={"text": "no author"})
    assert resp.status_code == 201
    assert resp.json()["author"] == "anonymous"


async def test_create_review_missing_text(client):
    resp = await client.post("/api/reviews/pg", json={"author": "a"})
    assert resp.status_code == 422  # validation error


# --------------- PATCH review ---------------


async def test_patch_resolve(client):
    create = await client.post("/api/reviews/pg", json={"author": "a", "text": "t"})
    rid = create.json()["id"]

    resp = await client.patch(f"/api/review/{rid}", json={"status": "resolved"})
    assert resp.status_code == 200
    data = resp.json()
    assert data["status"] == "resolved"
    assert data["resolved_by"] == "user"
    assert data["resolved_at"] is not None


async def test_patch_resolve_with_custom_resolver(client):
    create = await client.post("/api/reviews/pg", json={"author": "a", "text": "t"})
    rid = create.json()["id"]

    resp = await client.patch(
        f"/api/review/{rid}", json={"status": "resolved", "resolved_by": "bot"}
    )
    assert resp.json()["resolved_by"] == "bot"


async def test_patch_reopen(client):
    create = await client.post("/api/reviews/pg", json={"author": "a", "text": "t"})
    rid = create.json()["id"]

    await client.patch(f"/api/review/{rid}", json={"status": "resolved"})
    resp = await client.patch(f"/api/review/{rid}", json={"status": "open"})

    data = resp.json()
    assert data["status"] == "open"
    assert data["resolved_at"] is None
    assert data["resolved_by"] is None


async def test_patch_update_text(client):
    create = await client.post("/api/reviews/pg", json={"author": "a", "text": "old"})
    rid = create.json()["id"]

    resp = await client.patch(f"/api/review/{rid}", json={"text": "new"})
    assert resp.json()["text"] == "new"


async def test_patch_nonexistent(client):
    resp = await client.patch("/api/review/999", json={"status": "resolved"})
    assert resp.status_code == 404


# --------------- DELETE review ---------------


async def test_delete_review(client):
    create = await client.post("/api/reviews/pg", json={"author": "a", "text": "t"})
    rid = create.json()["id"]

    resp = await client.delete(f"/api/review/{rid}")
    assert resp.status_code == 200
    assert resp.json()["deleted"] is True

    # Verify it's gone
    all_resp = await client.get("/api/reviews")
    assert len(all_resp.json()) == 0


async def test_delete_nonexistent(client):
    resp = await client.delete("/api/review/999")
    assert resp.status_code == 404


# --------------- metadata ---------------


async def test_create_review_with_metadata(client):
    meta = {"element": "Button 'Submit'", "selector": "#submit-btn"}
    resp = await client.post(
        "/api/reviews/my-page",
        json={"author": "tester", "text": "Fix button", "metadata": meta},
    )
    assert resp.status_code == 201
    data = resp.json()
    assert data["metadata"] == meta
    assert data["metadata"]["element"] == "Button 'Submit'"
    assert data["metadata"]["selector"] == "#submit-btn"


async def test_get_reviews_returns_metadata(client):
    meta = {"element": "Input[email]", "selector": ".email-field"}
    await client.post(
        "/api/reviews/pg",
        json={"author": "a", "text": "Fix input", "metadata": meta},
    )
    resp = await client.get("/api/reviews/pg")
    data = resp.json()
    assert len(data) == 1
    assert data[0]["metadata"] == meta


async def test_create_review_without_metadata(client):
    resp = await client.post("/api/reviews/pg", json={"author": "a", "text": "no meta"})
    assert resp.status_code == 201
    data = resp.json()
    assert data["metadata"] is None


async def test_metadata_roundtrip(client):
    """Create with metadata, GET returns same dict, update metadata."""
    meta = {"element": "Heading 1", "selector": "h1.title", "fullPath": "body > main > h1.title"}
    create = await client.post("/api/reviews/pg", json={"author": "a", "text": "t", "metadata": meta})
    rid = create.json()["id"]

    # GET returns deserialized dict
    get_resp = await client.get("/api/reviews/pg")
    assert get_resp.json()[0]["metadata"] == meta

    # PATCH metadata
    new_meta = {"element": "Button", "selector": "#btn"}
    patch_resp = await client.patch(f"/api/review/{rid}", json={"metadata": new_meta})
    assert patch_resp.json()["metadata"] == new_meta
