"""Tests from the acme-crm-mcp demo. Run: pytest test_auth_practice.py"""
from auth_practice import insert_allowed, next_step, parse_challenge, visible_rows

ROWS = [
    {"id": "c_101", "tenant_id": "acme", "name": "Priya Shah"},
    {"id": "c_102", "tenant_id": "acme", "name": "Marcus Lee"},
    {"id": "c_103", "tenant_id": "acme", "name": "Sofia Alvarez"},
    {"id": "c_201", "tenant_id": "globex", "name": "Dana Kim"},
    {"id": "c_202", "tenant_id": "globex", "name": "Tom Becker"},
]
META = 'resource_metadata="http://localhost:8787/.well-known/oauth-protected-resource"'


def ids(rows):
    return [r["id"] for r in rows]


def test_what_each_connection_sees():
    # psql as the owner, policy not forced: every tenant's rows
    assert len(visible_rows(ROWS, is_owner=True, forced=False, tenant=None)) == 5
    # the app's role with no tenant set: nothing at all
    assert visible_rows(ROWS, is_owner=False, forced=True, tenant=None) == []
    assert ids(visible_rows(ROWS, False, True, "acme")) == ["c_101", "c_102", "c_103"]
    assert ids(visible_rows(ROWS, False, True, "globex")) == ["c_201", "c_202"]


def test_force_makes_the_owner_obey_too():
    # why the demo FORCEs RLS: an app that connected as the owner would otherwise see everything
    assert ids(visible_rows(ROWS, is_owner=True, forced=True, tenant="acme")) == ["c_101", "c_102", "c_103"]
    assert visible_rows(ROWS, is_owner=True, forced=True, tenant=None) == []


def test_with_check_on_writes():
    assert insert_allowed("acme", "acme")
    assert not insert_allowed("globex", "acme")    # a smuggled tenant can't be written
    assert not insert_allowed("acme", None)


def test_parse_the_demos_challenges():
    assert parse_challenge(f'Bearer error="insufficient_scope", scope="crm:write", {META}') == {
        "error": "insufficient_scope", "scope": "crm:write",
        "resource_metadata": "http://localhost:8787/.well-known/oauth-protected-resource"}
    assert parse_challenge(f'Bearer {META}, error="invalid_token"')["error"] == "invalid_token"


def test_401_and_403_mean_different_things():
    assert next_step(401, f"Bearer {META}") == "sign in"                                     # no token
    assert next_step(401, f'Bearer {META}, error="invalid_token"') == "get a new token"      # expired / wrong aud
    assert next_step(403, f'Bearer error="insufficient_scope", scope="crm:write", {META}') == "ask for crm:write"
    assert next_step(200) == "ok"
    assert next_step(429) == "fail"
