"""
Integration tests for Phase 7 admin AI config endpoints.

Promoted from Wave 0 xfail stubs in Plan 07-05.

Covers:
  - T-07-01: GET /api/admin/ai-config never returns api_key_enc (D-05/D-08)
  - D-08:    PUT /api/admin/ai-config writes active provider (admin AI Providers panel)
  - T-07-15: PUT /api/admin/ai-config is admin-only (non-admin gets 403)

All tests run against the in-memory SQLite fixture; no live services required.
"""
import pytest
import pytest_asyncio
from httpx import ASGITransport, AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession


# ── Helpers ───────────────────────────────────────────────────────────────────

async def _get_admin_client(db_session: AsyncSession) -> AsyncClient:
    """Return an AsyncClient with the DB dependency overridden to db_session."""
    from deps.db import get_db
    from main import app

    app.dependency_overrides[get_db] = lambda: db_session
    return AsyncClient(transport=ASGITransport(app=app), base_url="http://test")


# ── Tests ─────────────────────────────────────────────────────────────────────

@pytest.mark.asyncio
async def test_get_never_returns_key(
    async_client: AsyncClient,
    admin_user: dict,
    db_session: AsyncSession,
):
    """GET /api/admin/ai-config must never include api_key_enc or a plaintext key.

    Mitigates T-07-01: admin panel response whitelist (D-08).
    """
    # First PUT a provider config with an API key so the DB row exists
    put_resp = await async_client.put(
        "/api/admin/ai-config",
        json={"provider_id": "openai", "api_key": "sk-test-secret"},
        headers=admin_user["headers"],
    )
    assert put_resp.status_code == 200

    # GET must not expose the key in any form
    get_resp = await async_client.get(
        "/api/admin/ai-config",
        headers=admin_user["headers"],
    )
    assert get_resp.status_code == 200
    body_text = get_resp.text

    # Security assertions (T-07-01)
    assert "api_key_enc" not in body_text, "api_key_enc must never appear in GET response"
    assert "sk-test-secret" not in body_text, "plaintext API key must never appear in GET response"

    providers = get_resp.json()["providers"]
    assert len(providers) > 0, "providers list must not be empty"

    openai_row = next((p for p in providers if p["provider_id"] == "openai"), None)
    assert openai_row is not None, "openai provider must appear in response"
    assert "api_key_enc" not in openai_row, "api_key_enc key must not be present in provider dict"
    assert openai_row["has_api_key"] is True, "has_api_key must be True after saving a key"


@pytest.mark.asyncio
async def test_put_writes_active_provider(
    async_client: AsyncClient,
    admin_user: dict,
    db_session: AsyncSession,
):
    """PUT /api/admin/ai-config with is_active=True atomically flips active provider.

    Mitigates T-07-03: no dual-active race (D-08).
    After two sequential PUTs with is_active=True on different providers,
    exactly one row must have is_active=True.
    """
    from sqlalchemy import func, select
    from db.models import SystemSettings

    # PUT openai as active
    r1 = await async_client.put(
        "/api/admin/ai-config",
        json={"provider_id": "openai", "api_key": "sk-test", "is_active": True},
        headers=admin_user["headers"],
    )
    assert r1.status_code == 200
    assert r1.json()["has_api_key"] is True
    assert r1.json()["is_active"] is True

    # PUT anthropic as active (should atomically flip openai to inactive)
    r2 = await async_client.put(
        "/api/admin/ai-config",
        json={"provider_id": "anthropic", "is_active": True},
        headers=admin_user["headers"],
    )
    assert r2.status_code == 200
    assert r2.json()["is_active"] is True

    # DB assertion: exactly one row must be active
    count_result = await db_session.execute(
        select(func.count(SystemSettings.id)).where(
            SystemSettings.is_active.is_(True)
        )
    )
    active_count = count_result.scalar_one()
    assert active_count == 1, (
        f"Expected exactly 1 active provider after two PUTs with is_active=True, "
        f"got {active_count}"
    )


@pytest.mark.asyncio
async def test_put_admin_only(
    async_client: AsyncClient,
    auth_user: dict,
):
    """PUT /api/admin/ai-config by a regular (non-admin) user must return 403.

    Mitigates T-07-15: admin-only enforcement (D-08).
    """
    resp = await async_client.put(
        "/api/admin/ai-config",
        json={"provider_id": "openai", "api_key": "sk-test"},
        headers=auth_user["headers"],
    )
    assert resp.status_code == 403, (
        f"Expected 403 Forbidden for non-admin user, got {resp.status_code}"
    )
