"""Tests for the FastAPI router."""

from __future__ import annotations

import pytest
from fastapi import FastAPI
from httpx import ASGITransport, AsyncClient

from vault.config import SecretsConfig, init_secrets
from vault.router import create_secrets_router


@pytest.fixture()
def app():
    init_secrets(SecretsConfig(master_key="test-router-key"))
    application = FastAPI()
    application.include_router(create_secrets_router())
    return application


@pytest.fixture()
async def client(app):
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as c:
        yield c


class TestCreateSecret:
    async def test_create(self, client: AsyncClient):
        resp = await client.post("/secrets", json={"name": "db-pass", "value": "hunter2"})
        assert resp.status_code == 201
        data = resp.json()
        assert data["name"] == "db-pass"
        assert data["version"] == 1
        assert "value" not in data  # metadata only

    async def test_create_duplicate_returns_409(self, client: AsyncClient):
        await client.post("/secrets", json={"name": "dup", "value": "v1"})
        resp = await client.post("/secrets", json={"name": "dup", "value": "v2"})
        assert resp.status_code == 409

    async def test_create_with_tags(self, client: AsyncClient):
        resp = await client.post(
            "/secrets",
            json={"name": "tagged", "value": "val", "tags": {"env": "prod"}},
        )
        assert resp.status_code == 201
        assert resp.json()["tags"] == {"env": "prod"}


class TestGetSecret:
    async def test_get_existing(self, client: AsyncClient):
        await client.post("/secrets", json={"name": "key", "value": "secret123"})
        resp = await client.get("/secrets/key")
        assert resp.status_code == 200
        data = resp.json()
        assert data["value"] == "secret123"
        assert data["version"] == 1

    async def test_get_nonexistent_returns_404(self, client: AsyncClient):
        resp = await client.get("/secrets/nope")
        assert resp.status_code == 404


class TestListSecrets:
    async def test_list_empty(self, client: AsyncClient):
        resp = await client.get("/secrets")
        assert resp.status_code == 200
        assert resp.json() == []

    async def test_list_multiple(self, client: AsyncClient):
        await client.post("/secrets", json={"name": "a", "value": "1"})
        await client.post("/secrets", json={"name": "b", "value": "2"})
        resp = await client.get("/secrets")
        names = {s["name"] for s in resp.json()}
        assert names == {"a", "b"}

    async def test_list_excludes_values(self, client: AsyncClient):
        await client.post("/secrets", json={"name": "s", "value": "hidden"})
        resp = await client.get("/secrets")
        for item in resp.json():
            assert "value" not in item


class TestUpdateSecret:
    async def test_update_creates_new_version(self, client: AsyncClient):
        await client.post("/secrets", json={"name": "key", "value": "v1"})
        resp = await client.put("/secrets/key", json={"value": "v2"})
        assert resp.status_code == 200
        assert resp.json()["version"] == 2

    async def test_update_nonexistent_returns_404(self, client: AsyncClient):
        resp = await client.put("/secrets/nope", json={"value": "v"})
        assert resp.status_code == 404


class TestDeleteSecret:
    async def test_delete(self, client: AsyncClient):
        await client.post("/secrets", json={"name": "key", "value": "val"})
        resp = await client.delete("/secrets/key")
        assert resp.status_code == 204

    async def test_delete_nonexistent_returns_404(self, client: AsyncClient):
        resp = await client.delete("/secrets/nope")
        assert resp.status_code == 404

    async def test_deleted_not_gettable(self, client: AsyncClient):
        await client.post("/secrets", json={"name": "key", "value": "val"})
        await client.delete("/secrets/key")
        resp = await client.get("/secrets/key")
        assert resp.status_code == 404


class TestVersions:
    async def test_list_versions(self, client: AsyncClient):
        await client.post("/secrets", json={"name": "key", "value": "v1"})
        await client.put("/secrets/key", json={"value": "v2"})
        resp = await client.get("/secrets/key/versions")
        assert resp.status_code == 200
        versions = resp.json()
        assert len(versions) == 2
        assert versions[0]["version_number"] == 1
        assert versions[1]["version_number"] == 2

    async def test_versions_nonexistent_returns_404(self, client: AsyncClient):
        resp = await client.get("/secrets/nope/versions")
        assert resp.status_code == 404


class TestRotateEndpoint:
    async def test_rotate(self, client: AsyncClient):
        await client.post("/secrets", json={"name": "key", "value": "v1"})
        resp = await client.post("/secrets/key/rotate", json={"value": "rotated"})
        assert resp.status_code == 200
        assert resp.json()["version"] == 2
        # Verify the value actually changed
        get_resp = await client.get("/secrets/key")
        assert get_resp.json()["value"] == "rotated"

    async def test_rotate_nonexistent_returns_404(self, client: AsyncClient):
        resp = await client.post("/secrets/nope/rotate", json={"value": "v"})
        assert resp.status_code == 404
