"""
Regression tests for System Audit Log listing.

Covers the P0 production incident where `GET /api/v1/audit-logs`
returned 500 on every call because the route built
`PaginationMeta(..., total_pages=...)` while the schema defines `pages`.
"""

import pytest
import pytest_asyncio
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.security import create_access_token, hash_password
from app.models.lab import Lab
from app.models.user import User, UserRole
from app.repositories.permission_repository import PermissionRepository


@pytest_asyncio.fixture(autouse=True)
async def seed_perms(db_session: AsyncSession) -> None:
    """Seed system permissions for RBAC enforcement."""
    repo = PermissionRepository()
    await repo.seed_permissions(db_session)


@pytest_asyncio.fixture
async def audit_lab(db_session: AsyncSession) -> Lab:
    """Create primary test branch lab."""
    lab = Lab(name="Audit Trail Lab", address="Kathmandu")
    db_session.add(lab)
    await db_session.commit()
    await db_session.refresh(lab)
    return lab


@pytest_asyncio.fixture
async def audit_admin_token(db_session: AsyncSession, audit_lab: Lab) -> str:
    """Create branch admin user token (ADMIN role carries USER_READ)."""
    admin = User(
        lab_id=audit_lab.id,
        name="Audit Admin",
        phone="9818000001",
        role=UserRole.SUPERADMIN,
        hashed_password=hash_password("AdminPass123!"),
        is_active=True,
    )
    db_session.add(admin)
    await db_session.commit()
    await db_session.refresh(admin)

    return create_access_token(
        subject=str(admin.id),
        extra_claims={
            "phone": admin.phone,
            "role": admin.role.value,
            "lab_id": str(audit_lab.id),
        },
    )


@pytest.mark.asyncio
class TestAuditLogListing:
    """Listing must return 200 with a well-formed pagination envelope."""

    async def test_list_audit_logs_returns_200_with_pages_meta(
        self,
        client: AsyncClient,
        audit_admin_token: str,
    ) -> None:
        resp = await client.get(
            "/api/v1/audit-logs",
            params={"limit": 5},
            headers={"Authorization": f"Bearer {audit_admin_token}"},
        )
        assert resp.status_code == 200, resp.text
        body = resp.json()
        assert body["success"] is True
        assert isinstance(body["data"], list)
        assert "pages" in body["meta"], f"meta missing 'pages': {body['meta']}"
        assert body["meta"]["total"] >= 0

    async def test_list_audit_logs_category_filter(
        self,
        client: AsyncClient,
        audit_admin_token: str,
    ) -> None:
        resp = await client.get(
            "/api/v1/audit-logs",
            params={"category": "ADMIN", "limit": 5},
            headers={"Authorization": f"Bearer {audit_admin_token}"},
        )
        assert resp.status_code == 200, resp.text

    async def test_audit_metrics_returns_counts(
        self,
        client: AsyncClient,
        audit_admin_token: str,
    ) -> None:
        resp = await client.get(
            "/api/v1/audit-logs/metrics",
            headers={"Authorization": f"Bearer {audit_admin_token}"},
        )
        assert resp.status_code == 200, resp.text
        assert resp.json()["data"]["total_events"] >= 0


@pytest.mark.asyncio
async def test_audit_reads_do_not_fabricate_events(client: AsyncClient, audit_admin_token: str) -> None:
    headers = {"Authorization": f"Bearer {audit_admin_token}"}
    logs = await client.get("/api/v1/audit-logs", headers=headers)
    metrics = await client.get("/api/v1/audit-logs/metrics", headers=headers)
    assert logs.json()["meta"]["total"] == 0
    assert logs.json()["data"] == []
    assert metrics.json()["data"]["total_events"] == 0


@pytest.mark.asyncio
async def test_audit_permission_and_branch_scope(
    client: AsyncClient, db_session: AsyncSession, audit_lab: Lab
) -> None:
    from sqlalchemy import select

    from app.models.user import Permission, UserPermissionOverride

    user = User(
        lab_id=audit_lab.id,
        name="Accountant",
        phone="9818000002",
        role=UserRole.ACCOUNTANT,
        hashed_password=hash_password("Password123!"),
        is_active=True,
    )
    db_session.add(user)
    await db_session.commit()
    headers = {"Authorization": f"Bearer {create_access_token(str(user.id))}"}
    assert (await client.get("/api/v1/audit-logs", headers=headers)).status_code == 403
    permission = (
        await db_session.execute(select(Permission).where(Permission.code == "audit:read"))
    ).scalar_one()
    db_session.add(UserPermissionOverride(user_id=user.id, permission_id=permission.id, is_granted=True))
    await db_session.commit()
    assert (await client.get("/api/v1/audit-logs", headers=headers)).status_code == 200
    other_lab = Lab(name="Other audit branch", address="Pokhara")
    db_session.add(other_lab)
    await db_session.commit()
    for path in ("/api/v1/audit-logs", "/api/v1/audit-logs/metrics"):
        response = await client.get(path, headers=headers, params={"lab_id": str(other_lab.id)})
        assert response.status_code == 403
