-- =============================================================================
-- Global Rules Tests
-- =============================================================================
-- Tests system-wide rules via morbac.global_rules.
--
-- Scenarios:
--   1. No global rule: Karl (no role) is denied by default
--   2. Global permission (user_id=NULL): all users gain access
--   3. Global permission (user_id=uuid): only that user gains access
--   4. Global prohibition (user_id=NULL): all users are denied regardless of role
--   5. Global prohibition (user_id=uuid): only that user is denied
--   6. Priority: global permission with higher priority overrides global prohibition
--   7. Priority: high-priority global prohibition overrides role-based permission
--   8. NULL activity/view wildcards (no hierarchy needed)
--   9. Activity/view hierarchy applies when activity/view are set
--  10. Temporal global rules (valid_from / valid_until)
--
-- Prerequisites: 00_setup.sql -> 12_user_rules.sql
-- =============================================================================

\echo ''
\echo '================================================================'
\echo '13 -- GLOBAL RULES'
\echo '================================================================'

-- ---------------------------------------------------------------------------
-- Section 1: No global rule -- Karl (no role) is denied
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 1. No global rule: access denied ---'

SELECT morbac.t('Karl (no role) reads GlobalTech contracts [no global rule]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'contracts'
    ), FALSE);

SELECT morbac.t('Karl (no role) reads Engineering contracts [no global rule]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000002'::uuid,
        'read', 'contracts'
    ), FALSE);

-- ---------------------------------------------------------------------------
-- Section 2: Global permission (user_id=NULL) -- all users gain access
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 2. Global permission, user_id=NULL: all users ---'

INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
VALUES (
    NULL,
    'read', 'contracts',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'permission'
);

-- Karl (no role) can now read contracts in any org
SELECT morbac.t('Karl reads GlobalTech contracts [global permission, any user]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'contracts'
    ), TRUE);

SELECT morbac.t('Karl reads Engineering contracts [global permission covers all orgs]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000002'::uuid,
        'read', 'contracts'
    ), TRUE);

-- Dave (employee) also benefits
SELECT morbac.t('Dave reads GlobalTech contracts [global permission, any user]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000004'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'contracts'
    ), TRUE);

DELETE FROM morbac.global_rules WHERE user_id IS NULL AND activity = 'read' AND view = 'contracts';

-- ---------------------------------------------------------------------------
-- Section 3: Global permission (user_id=uuid) -- specific user only
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 3. Global permission, user_id=Karl only ---'

INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
VALUES (
    '30000000-0000-0000-0000-000000000011', -- Karl
    'read', 'contracts',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'permission'
);

SELECT morbac.t('Karl reads GlobalTech contracts [user_id-specific global permission]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'contracts'
    ), TRUE);

-- Dave has no role permission on contracts and no global rule for him
SELECT morbac.t('Dave reads GlobalTech contracts [user_id-specific rule does not cover Dave]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000004'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'contracts'
    ), FALSE);

DELETE FROM morbac.global_rules
WHERE user_id = '30000000-0000-0000-0000-000000000011'
  AND activity = 'read' AND view = 'contracts';

-- ---------------------------------------------------------------------------
-- Section 4: Global prohibition (user_id=NULL) -- all users denied regardless of role
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 4. Global prohibition, user_id=NULL: all users denied ---'

-- Dave (employee) has a role-based permission on public_data from setup
SELECT morbac.t('Dave reads GlobalTech public_data [role permission before global prohibition]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000004'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'public_data'
    ), TRUE);

INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
VALUES (
    NULL,
    'read', 'public_data',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'prohibition'
);

SELECT morbac.t('Dave reads GlobalTech public_data [global prohibition blocks role permission]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000004'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'public_data'
    ), FALSE);

-- Karl (no role) is also denied
SELECT morbac.t('Karl reads GlobalTech public_data [global prohibition, no role]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'public_data'
    ), FALSE);

-- Alice (CEO, highest role) is also denied
SELECT morbac.t('Alice reads GlobalTech public_data [global prohibition overrides CEO role]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000001'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'public_data'
    ), FALSE);

DELETE FROM morbac.global_rules WHERE user_id IS NULL AND activity = 'read' AND view = 'public_data';

-- ---------------------------------------------------------------------------
-- Section 5: Global prohibition (user_id=uuid) -- specific user denied only
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 5. Global prohibition, user_id=Dave only ---'

INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
VALUES (
    '30000000-0000-0000-0000-000000000004', -- Dave
    'read', 'public_data',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'prohibition'
);

SELECT morbac.t('Dave reads GlobalTech public_data [user_id-specific global prohibition]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000004'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'public_data'
    ), FALSE);

-- Carol (manager) is unaffected
SELECT morbac.t('Carol reads GlobalTech public_data [global prohibition does not affect Carol]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000003'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'public_data'
    ), TRUE);

DELETE FROM morbac.global_rules
WHERE user_id = '30000000-0000-0000-0000-000000000004'
  AND activity = 'read' AND view = 'public_data';

-- ---------------------------------------------------------------------------
-- Section 6: Priority -- global permission overrides global prohibition
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 6. Priority: global permission > global prohibition ---'

INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality, priority)
VALUES (
    NULL,
    'read', 'public_data',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'prohibition', 5
);

INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality, priority)
VALUES (
    '30000000-0000-0000-0000-000000000004', -- Dave
    'read', 'public_data',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'permission', 10
);

SELECT morbac.t('Dave reads GlobalTech public_data [priority-10 global permission beats priority-5 global prohibition]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000004'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'public_data'
    ), TRUE);

-- Karl has no user_id-specific permission -- global prohibition still blocks him
SELECT morbac.t('Karl reads GlobalTech public_data [global prohibition still blocks non-exempted user]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'public_data'
    ), FALSE);

DELETE FROM morbac.global_rules WHERE activity = 'read' AND view = 'public_data';

-- ---------------------------------------------------------------------------
-- Section 7: Priority -- high-priority global prohibition overrides role permission
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 7. Priority: global prohibition > role permission ---'

-- Dave has role-based read on public_data (priority 0 by default)
SELECT morbac.t('Dave reads GlobalTech public_data [role permission, no global rule]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000004'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'public_data'
    ), TRUE);

INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality, priority)
VALUES (
    NULL,
    'read', 'public_data',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'prohibition', 100
);

SELECT morbac.t('Dave reads GlobalTech public_data [priority-100 global prohibition beats role permission]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000004'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'public_data'
    ), FALSE);

DELETE FROM morbac.global_rules WHERE activity = 'read' AND view = 'public_data';

-- ---------------------------------------------------------------------------
-- Section 8: NULL activity/view wildcards
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 8. NULL wildcards: activity=NULL and view=NULL ---'

-- view=NULL grants read on every view for Karl (no role)
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
VALUES (
    '30000000-0000-0000-0000-000000000011', -- Karl
    'read', NULL,
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'permission'
);

SELECT morbac.t('Karl reads GlobalTech contracts [view=NULL global permission]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'contracts'
    ), TRUE);

SELECT morbac.t('Karl reads GlobalTech financial_data [view=NULL global permission]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'financial_data'
    ), TRUE);

DELETE FROM morbac.global_rules
WHERE user_id = '30000000-0000-0000-0000-000000000011'
  AND activity = 'read' AND view IS NULL;

-- activity=NULL and view=NULL grants everything
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
VALUES (
    '30000000-0000-0000-0000-000000000011', -- Karl
    NULL, NULL,
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'permission'
);

SELECT morbac.t('Karl deletes GlobalTech contracts [activity=NULL, view=NULL global permission]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'delete', 'contracts'
    ), TRUE);

DELETE FROM morbac.global_rules
WHERE user_id = '30000000-0000-0000-0000-000000000011'
  AND activity IS NULL AND view IS NULL;

-- ---------------------------------------------------------------------------
-- Section 9: Activity/view hierarchy applies when activity/view are set
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 9. Activity/view hierarchy ---'

-- financial_data is a child of documents (view hierarchy from setup)
-- A global permission on 'documents' should cover 'financial_data'
INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality)
VALUES (
    '30000000-0000-0000-0000-000000000011', -- Karl
    'read', 'documents',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'permission'
);

SELECT morbac.t('Karl reads GlobalTech financial_data [global permission on documents covers child view]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'financial_data'
    ), TRUE);

DELETE FROM morbac.global_rules
WHERE user_id = '30000000-0000-0000-0000-000000000011'
  AND activity = 'read' AND view = 'documents';

-- ---------------------------------------------------------------------------
-- Section 10: Temporal global rules
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 10. Temporal global rules ---'

INSERT INTO morbac.global_rules (user_id, activity, view, context_id, modality, valid_from, valid_until)
VALUES (
    '30000000-0000-0000-0000-000000000011', -- Karl
    'read', 'contracts',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'permission',
    now() - interval '1 hour',
    now() + interval '1 day'
);

SELECT morbac.t('Karl reads GlobalTech contracts [temporal global rule, active]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'contracts'
    ), TRUE);

UPDATE morbac.global_rules
SET valid_until = now() - interval '1 second'
WHERE user_id = '30000000-0000-0000-0000-000000000011'
  AND activity = 'read' AND view = 'contracts';

SELECT morbac.t('Karl reads GlobalTech contracts [temporal global rule, expired]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'contracts'
    ), FALSE);

DELETE FROM morbac.global_rules
WHERE user_id = '30000000-0000-0000-0000-000000000011'
  AND activity = 'read' AND view = 'contracts';

\echo ''
\echo '=== Global Rules Tests Completed ==='
