"""Tests for the /api/keys/* management endpoints."""

from __future__ import annotations

import pytest
from httpx import ASGITransport, AsyncClient

from llmhosts.proxy.app import create_app
from llmhosts.proxy.dispatcher import BackendDispatcher


@pytest.fixture
def app():
    return create_app()


@pytest.fixture
async def client(app):
    # Manually create dispatcher (same as conftest pattern -- ASGITransport
    # doesn't trigger lifespan events so /v1/models needs dispatcher).
    dispatcher = BackendDispatcher()
    await dispatcher.startup()
    app.state.dispatcher = dispatcher

    transport = ASGITransport(app=app, raise_app_exceptions=False)
    async with AsyncClient(transport=transport, base_url="http://test") as c:
        yield c

    await dispatcher.shutdown()


@pytest.mark.asyncio
@pytest.mark.unit
async def test_create_key(client: AsyncClient) -> None:
    resp = await client.post("/api/keys", json={"label": "my-laptop", "plan": "free"})
    assert resp.status_code == 201
    data = resp.json()
    assert "key_id" in data
    assert "raw_key" in data
    assert data["label"] == "my-laptop"
    assert data["plan"] == "free"
    assert data["raw_key"].startswith("lmh_")  # prefixed keys


@pytest.mark.asyncio
@pytest.mark.unit
async def test_list_keys(client: AsyncClient) -> None:
    # Create a key first
    await client.post("/api/keys", json={"label": "test-key", "plan": "pro"})
    resp = await client.get("/api/keys")
    assert resp.status_code == 200
    keys = resp.json()["keys"]
    assert len(keys) >= 1
    assert "raw_key" not in str(keys)  # raw key never exposed in list
    assert keys[-1]["label"] == "test-key"
    assert keys[-1]["plan"] == "pro"


@pytest.mark.asyncio
@pytest.mark.unit
async def test_revoke_key(client: AsyncClient) -> None:
    create_resp = await client.post("/api/keys", json={"label": "to-revoke"})
    key_id = create_resp.json()["key_id"]
    resp = await client.delete(f"/api/keys/{key_id}")
    assert resp.status_code == 200
    # Verify key no longer works
    list_resp = await client.get("/api/keys")
    ids = [k["id"] for k in list_resp.json()["keys"]]
    assert key_id not in ids


@pytest.mark.asyncio
@pytest.mark.unit
async def test_revoke_nonexistent_key(client: AsyncClient) -> None:
    resp = await client.delete("/api/keys/nonexistent")
    assert resp.status_code == 404


@pytest.mark.asyncio
@pytest.mark.unit
async def test_create_key_missing_label(client: AsyncClient) -> None:
    resp = await client.post("/api/keys", json={})
    assert resp.status_code == 422


@pytest.mark.asyncio
@pytest.mark.unit
async def test_created_key_authenticates(client: AsyncClient) -> None:
    create_resp = await client.post("/api/keys", json={"label": "auth-test"})
    raw_key = create_resp.json()["raw_key"]
    # Use the key to hit an authenticated endpoint
    resp = await client.get("/v1/models", headers={"Authorization": f"Bearer {raw_key}"})
    assert resp.status_code == 200
