"""Integration tests for app.api.v1.api_management — API keys, usage logs, webhooks."""

import uuid

import pytest
import pytest_asyncio
from sqlalchemy import select

from app.models.operations import ApiKey


@pytest_asyncio.fixture
async def auth_ctx(client):
    """Register a user and return (headers, user_id)."""
    email = f"t{uuid.uuid4().hex[:6]}@test.cn"
    resp = await client.post("/api/v1/auth/register", json={
        "email": email, "password": "Test1234", "display_name": "TestUser",
    })
    assert resp.status_code == 200
    data = resp.json()
    headers = {"Authorization": f"Bearer {data['token']['access_token']}"}
    user_id = uuid.UUID(data["user"]["id"])
    return headers, user_id


@pytest_asyncio.fixture
async def seed_key(auth_ctx, db):
    """Seed an API key for a tenant."""
    headers, uid = auth_ctx
    from app.models.user import UserTenant
    r = await db.execute(select(UserTenant.tenant_id).where(UserTenant.user_id == uid))
    tenant_id = r.scalar()

    import hashlib
    raw = "sk-" + "a" * 64
    key = ApiKey(id=uuid.uuid4(), tenant_id=tenant_id, user_id=uid,
                 name="Test Key", key_prefix="sk-test", key_hash=hashlib.sha256(raw.encode()).hexdigest(),
                 scopes=["read"], is_active=True)
    db.add(key)
    await db.commit()
    return headers, uid, key


# ── List Keys ──


@pytest.mark.asyncio
async def test_list_keys_no_auth(client):
    """GET /keys without auth returns 401."""
    r = await client.get("/api/v1/api-management/keys")
    assert r.status_code == 401


@pytest.mark.asyncio
async def test_list_keys_empty(client, auth_headers):
    """GET /keys with auth returns empty list."""
    r = await client.get("/api/v1/api-management/keys", headers=auth_headers)
    assert r.status_code == 200
    data = r.json()
    assert data["items"] == []
    assert data["total"] == 0


@pytest.mark.asyncio
async def test_list_keys_with_data(client, seed_key):
    """GET /keys returns seeded keys."""
    headers, _, key = seed_key
    r = await client.get("/api/v1/api-management/keys", headers=headers)
    assert r.status_code == 200
    data = r.json()
    assert data["total"] >= 1
    names = {k["name"] for k in data["items"]}
    assert "Test Key" in names


# ── Create Key ──


@pytest.mark.asyncio
async def test_create_key_no_auth(client):
    """POST /keys without auth returns 403 (CSRF)."""
    r = await client.post("/api/v1/api-management/keys", json={"name": "New Key"})
    assert r.status_code == 403


@pytest.mark.asyncio
async def test_create_key_success(client, auth_headers):
    """POST /keys creates a new API key."""
    r = await client.post("/api/v1/api-management/keys", json={"name": "My Key", "scopes": ["read", "write"]},
                          headers=auth_headers)
    assert r.status_code == 200
    data = r.json()
    assert data["status"] == "created"
    assert data["api_key"].startswith("sk-")
    assert data["prefix"] == data["api_key"][:12]


# ── Revoke Key ──


@pytest.mark.asyncio
async def test_revoke_key_no_auth(client):
    """DELETE /keys without auth — endpoint lacks auth guard, returns 403 (CSRF)."""
    r = await client.delete(f"/api/v1/api-management/keys/{uuid.uuid4()}")
    assert r.status_code == 403


@pytest.mark.asyncio
async def test_revoke_key_not_found(client, auth_headers):
    """DELETE /keys for non-existent key returns 404."""
    r = await client.delete(f"/api/v1/api-management/keys/{uuid.uuid4()}", headers=auth_headers)
    assert r.status_code == 404


@pytest.mark.asyncio
async def test_revoke_key_success(client, seed_key):
    """DELETE /keys revokes the key."""
    headers, _, key = seed_key
    r = await client.delete(f"/api/v1/api-management/keys/{key.id}", headers=headers)
    assert r.status_code == 200
    assert r.json()["status"] == "revoked"

    # Verify via list endpoint
    r = await client.get("/api/v1/api-management/keys", headers=headers)
    assert r.status_code == 200
    keys = r.json()["items"]
    assert not any(k["id"] == str(key.id) for k in keys)


# ── Usage Log ──


@pytest.mark.asyncio
async def test_api_usage_no_auth(client):
    """GET /usage without auth returns 401."""
    r = await client.get("/api/v1/api-management/usage")
    assert r.status_code == 401


@pytest.mark.asyncio
async def test_api_usage_empty(client, auth_headers):
    """GET /usage with auth returns empty list."""
    r = await client.get("/api/v1/api-management/usage", headers=auth_headers)
    assert r.status_code == 200
    data = r.json()
    assert data["items"] == []
    assert data["total"] == 0


# ── Webhooks (endpoints lack get_current_user, so tenant_ctx is never set) ──


@pytest.mark.asyncio
async def test_list_webhooks_no_auth(client):
    """GET /webhooks without auth returns 401 (now has get_current_user)."""
    r = await client.get("/api/v1/api-management/webhooks")
    assert r.status_code == 401


@pytest.mark.asyncio
async def test_list_webhooks_with_auth(client, auth_headers):
    """GET /webhooks with auth returns empty list."""
    r = await client.get("/api/v1/api-management/webhooks", headers=auth_headers)
    assert r.status_code == 200
    data = r.json()
    assert data["items"] == []
    assert data["total"] == 0


@pytest.mark.asyncio
async def test_create_webhook_no_auth(client):
    """POST /webhooks without auth returns 403 (CSRF)."""
    r = await client.post("/api/v1/api-management/webhooks",
                          json={"url": "https://example.com/hook", "events": ["literature.new"]})
    assert r.status_code == 403


@pytest.mark.asyncio
async def test_create_webhook_success(client, auth_headers):
    """POST /webhooks creates a webhook."""
    r = await client.post("/api/v1/api-management/webhooks",
                          json={"url": "https://hooks.example.com/callback", "events": ["literature.new"]},
                          headers=auth_headers)
    assert r.status_code == 200
    assert r.json()["status"] == "created"

    r = await client.get("/api/v1/api-management/webhooks", headers=auth_headers)
    assert r.status_code == 200
    urls = [h["url"] for h in r.json()["items"]]
    assert "https://hooks.example.com/callback" in urls


@pytest.mark.asyncio
async def test_delete_webhook_no_auth(client):
    """DELETE /webhooks without auth returns 403 (CSRF)."""
    r = await client.delete("/api/v1/api-management/webhooks/some-id")
    assert r.status_code == 403


@pytest.mark.asyncio
async def test_create_delete_webhook(client, auth_headers):
    """Create then delete a webhook."""
    r = await client.post("/api/v1/api-management/webhooks",
                          json={"url": "https://hooks.example.com/del", "events": ["literature.update"]},
                          headers=auth_headers)
    assert r.status_code == 200

    r = await client.get("/api/v1/api-management/webhooks", headers=auth_headers)
    hook_id = r.json()["items"][0]["id"]

    r = await client.delete(f"/api/v1/api-management/webhooks/{hook_id}", headers=auth_headers)
    assert r.status_code == 200
    assert r.json()["status"] == "deleted"

    r = await client.get("/api/v1/api-management/webhooks", headers=auth_headers)
    assert r.json()["total"] == 0
