def api(test_app):
    """Fresh TestClient with a clean database and one registered+logged-in user."""
    from fastapi.testclient import TestClient
    from sqlalchemy import create_engine, text

    # wipe all data (keep schema)
    eng = create_engine(TEST_DATABASE_URL)
    with eng.connect() as c:
        for t in _TRUNCATE:
            try:
                c.execute(text(f'TRUNCATE TABLE "{t}" RESTART IDENTITY CASCADE'))
            except Exception:
                pass
        c.commit()
    eng.dispose()

    with TestClient(test_app) as client:
        em = f"t_{uuid.uuid4().hex[:10]}@example.com"
        pw = "TestPass#12345"
        r = client.post("/auth/register", json={"email": em, "password": pw, "full_name": "Tester"})
        assert r.status_code in (200, 201), f"register failed: {r.status_code} {r.text[:300]}"
        r = client.post("/auth/login", json={"email": em, "password": pw})
        assert r.status_code == 200, f"login failed: {r.status_code} {r.text[:300]}"
        client.email, client.password = em, pw
        yield client


@pytest.fixture(scope="session")
def db_engine(test_app):
    from sqlalchemy import create_engine

    eng = create_engine(TEST_DATABASE_URL, pool_pre_ping=True)
    yield eng
    eng.dispose()


@pytest.fixture()
def db(db_engine):
    """Plain sync session on the test DB (for direct row assertions)."""
    from sqlalchemy.orm import Session

    with Session(db_engine, expire_on_commit=False) as s:
        yield s


def csrf_of(client) -> str:
    """Read the CSRF token from the client's cookie jar."""
    for c in client.cookies.jar:
        if c.name == "mailer_csrf":
            return c.value
    raise AssertionError("CSRF cookie missing after login")
