"""Covers app/core/permissions.py::require_permission — before Pillar 2,
Role.action_matrix was stored and editable in the UI but never checked
anywhere, so any authenticated caller could do anything regardless of their
assigned role. These tests pin down that a role missing an action gets a
403, a role holding it gets through, and any is_system_role role bypasses
the check entirely."""

from app.core.auth import create_access_token
from tests.conftest import AsyncSessionLocal
from app.models.identity import Role, User, UserRole


async def _make_user_with_role(tenant_id, action_matrix: dict, *, is_system_role: bool = False):
    async with AsyncSessionLocal() as db:
        async with db.begin():
            role = Role(tenant_id=tenant_id, name="Throwaway Role", is_system_role=is_system_role, action_matrix=action_matrix)
            db.add(role)
            await db.flush()

            user = User(tenant_id=tenant_id, name="Throwaway User", email=f"throwaway-{role.id}@example.com", status="active")
            db.add(user)
            await db.flush()

            db.add(UserRole(user_id=user.id, role_id=role.id))
            await db.flush()
            return user.id, role.id


async def test_view_only_role_can_list_but_not_create(client, test_tenant):
    user_id, _ = await _make_user_with_role(test_tenant["tenant_id"], {"masters": ["view"]})
    token = create_access_token(tenant_id=test_tenant["tenant_id"], user_id=user_id, vendor_id=None)
    headers = {"Authorization": f"Bearer {token}"}

    list_resp = await client.get("/masters", headers=headers)
    assert list_resp.status_code == 200

    create_resp = await client.post(
        "/masters",
        headers=headers,
        json={"name": "Should Not Be Created", "field_schema": [{"name": "x", "type": "text"}]},
    )
    assert create_resp.status_code == 403


async def test_role_with_no_matrix_entry_for_module_is_denied(client, test_tenant):
    user_id, _ = await _make_user_with_role(test_tenant["tenant_id"], {"forms": ["view"]})
    token = create_access_token(tenant_id=test_tenant["tenant_id"], user_id=user_id, vendor_id=None)
    resp = await client.get("/masters", headers={"Authorization": f"Bearer {token}"})
    assert resp.status_code == 403


async def test_role_with_create_permission_can_create(client, test_tenant):
    user_id, _ = await _make_user_with_role(test_tenant["tenant_id"], {"masters": ["view", "create"]})
    token = create_access_token(tenant_id=test_tenant["tenant_id"], user_id=user_id, vendor_id=None)
    resp = await client.post(
        "/masters",
        headers={"Authorization": f"Bearer {token}"},
        json={"name": "Permitted Create", "field_schema": [{"name": "x", "type": "text"}]},
    )
    assert resp.status_code == 201


async def test_system_role_bypasses_matrix_entirely(client, test_tenant):
    """is_system_role=True must always pass, even with an empty action_matrix."""
    user_id, _ = await _make_user_with_role(test_tenant["tenant_id"], {}, is_system_role=True)
    token = create_access_token(tenant_id=test_tenant["tenant_id"], user_id=user_id, vendor_id=None)
    resp = await client.post(
        "/masters",
        headers={"Authorization": f"Bearer {token}"},
        json={"name": "System Role Create", "field_schema": [{"name": "x", "type": "text"}]},
    )
    assert resp.status_code == 201


async def test_admin_fixture_is_system_role_and_passes_everything(client, auth_headers):
    resp = await client.post(
        "/masters",
        headers=auth_headers,
        json={"name": "Admin Fixture Create", "field_schema": [{"name": "x", "type": "text"}]},
    )
    assert resp.status_code == 201
