"""Tests for the get_permissions hook consumer chain (contract 0.10.0).

Pins full_permission_catalog() and its consumers: the core catalog holds no
plugin permissions, an enabled plugin's permissions merge in and drop out when
disabled, seeding is idempotent, API-token scope validation follows the enabled
set, and the role grid groups plugin categories.

Plugin enabled-state is monkeypatched (not persisted) so these tests do not
mutate the shared instance/plugins.json registry file.
"""

from shopdb.core.models import Permission, full_permission_catalog
from shopdb.core.models.apitoken import ApiToken

# Permission-owning plugin domains that must NOT live in the core catalog.
PLUGIN_PREFIXES = ('machines.', 'computers.', 'printers.', 'network.', 'kb.',
                   'notifications.', 'usb.', 'warranty.', 'measuringtools.')


def test_core_catalog_excludes_plugin_permissions():
    """Permission.CORE_PERMISSIONS holds only genuinely core permissions."""
    names = {n for n, _d, _c in Permission.CORE_PERMISSIONS}
    for name in names:
        assert not name.startswith(PLUGIN_PREFIXES), (
            f'{name} is a plugin permission and must move to its plugin hook')
    # Core sets stay put.
    assert 'assets.edit' in names
    assert 'settings.edit' in names
    assert 'collector.ingest' in names


def test_enabled_plugin_permissions_merge(app, monkeypatch):
    """An enabled plugin's permissions appear in full_permission_catalog()."""
    pm = app.extensions['plugin_manager']
    monkeypatch.setattr(pm.registry, 'is_enabled', lambda name: True)
    with app.app_context():
        names = {n for n, _d, _c in full_permission_catalog()}
    assert 'machines.edit' in names
    assert 'printers.edit' in names
    # core still present alongside plugin permissions
    assert 'assets.edit' in names


def test_disabled_plugin_permissions_drop_out(app, monkeypatch):
    """A disabled plugin's permissions disappear from the catalog."""
    pm = app.extensions['plugin_manager']
    monkeypatch.setattr(pm.registry, 'is_enabled',
                        lambda name: name != 'machines')
    with app.app_context():
        names = {n for n, _d, _c in full_permission_catalog()}
    assert 'machines.edit' not in names
    assert 'printers.edit' in names  # other plugins still enabled


def test_seed_is_idempotent(app, db, monkeypatch):
    """Seeding the full catalog twice creates each permission once."""
    pm = app.extensions['plugin_manager']
    monkeypatch.setattr(pm.registry, 'is_enabled', lambda name: True)
    with app.app_context():
        first = Permission.seed()
        db.session.commit()
        assert first > len(Permission.CORE_PERMISSIONS)  # plugins contributed
        second = Permission.seed()
        db.session.commit()
        assert second == 0


def test_token_scope_validation_follows_enabled_set(app, monkeypatch):
    """A plugin permission is an accepted scope only while the plugin is enabled."""
    pm = app.extensions['plugin_manager']
    with app.app_context():
        monkeypatch.setattr(pm.registry, 'is_enabled', lambda name: True)
        assert ApiToken.unknown_scope_names(['machines.edit']) == []
        assert ApiToken.unknown_scope_names(['assets.edit']) == []

        monkeypatch.setattr(pm.registry, 'is_enabled',
                            lambda name: name != 'machines')
        assert ApiToken.unknown_scope_names(['machines.edit']) == ['machines.edit']


def test_list_permissions_endpoint_groups_plugin_category(
        app, client, auth_headers, monkeypatch):
    """GET /api/users/permissions surfaces enabled plugins' categories."""
    pm = app.extensions['plugin_manager']
    monkeypatch.setattr(pm.registry, 'is_enabled', lambda name: True)
    response = client.get('/api/users/permissions', headers=auth_headers)
    assert response.status_code == 200, response.get_json()
    grouped = response.get_json()['data']['grouped']
    assert 'assets' in grouped       # core category always present
    assert 'machines' in grouped     # enabled plugin category merged in
