-- =============================================================================
-- Cross-Organization Rules Tests
-- =============================================================================
-- Tests inter-organizational access via the cross_org_rules table.
--
-- Scenarios:
--   1. No cross-org rule: users in org A cannot access org B resources
--   2. Cross-org permission: specific role in source org can access target org
--   3. User must hold role in source org (not just any role)
--   4. Cross-org prohibition: blocks access even if there's a regular permission
--   5. Cross-org rules combine with activity hierarchy
--   6. Cross-org rules combine with view hierarchy
--   7. Temporal cross-org rules (valid_from / valid_until)
--
-- Company context:
--   Judy (sales_rep at Sales) is allowed to read GlobalTech reports via cross-org rule
--   Nina (eng_auditor at Engineering) has a temporal cross-org rule to read GlobalTech audit_logs
--   Diana (sales_manager at Sales) has a cross-org prohibition on writing Engineering docs
--
-- Prerequisites: 00_setup.sql -> 05_temporal.sql
-- =============================================================================

\echo ''
\echo '================================================================'
\echo '06 — CROSS-ORGANIZATIONAL RULES'
\echo '================================================================'

-- ---------------------------------------------------------------------------
-- Setup: additional roles and users for cross-org scenarios
-- ---------------------------------------------------------------------------

-- Nina: eng_auditor role in Engineering Dept
INSERT INTO morbac.roles (id, org_id, name, description) VALUES
    ('20000000-0002-0000-0000-000000000003', '10000000-0000-0000-0000-000000000002', 'eng_auditor', 'Engineering Auditor');

INSERT INTO morbac.user_roles (user_id, role_id, org_id) VALUES
    ('30000000-0000-0000-0000-000000000014', '20000000-0002-0000-0000-000000000003', '10000000-0000-0000-0000-000000000002');

-- Rules for eng_auditor in Engineering
INSERT INTO morbac.rules (org_id, role_id, activity, view, context_id, modality)
SELECT o.id, r.id, 'read', 'audit_logs', c.id, 'permission'
FROM morbac.orgs o
JOIN morbac.roles r ON r.org_id = o.id AND r.name = 'eng_auditor'
JOIN morbac.contexts c ON c.name = 'always'
WHERE o.name = 'Engineering Dept';

-- Verify nina's role was set up correctly
SELECT morbac.t('Nina has eng_auditor role at Engineering',
    morbac.user_has_role(
        '30000000-0000-0000-0000-000000000014'::uuid,
        '10000000-0000-0000-0000-000000000002'::uuid,
        'eng_auditor'
    ), TRUE);

-- ---------------------------------------------------------------------------
-- Section 1: No cross-org rule — access between orgs is denied by default
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 1. No cross-org rule: access denied by default ---'

-- Dave (employee at GlobalTech) has no role in Engineering and no cross-org rule
SELECT morbac.t('Dave (GlobalTech employee) reads Engineering documents [no cross-org rule]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000004'::uuid,
        '10000000-0000-0000-0000-000000000002'::uuid,
        'read', 'documents'
    ), FALSE);

-- Judy (Engineering engineer) accesses GlobalTech financial_data (no cross-org rule yet)
SELECT morbac.t('Judy (Engineering engineer) reads GlobalTech financial_data [no cross-org rule]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000010'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'financial_data'
    ), FALSE);

-- ---------------------------------------------------------------------------
-- Section 2: Cross-org permission — Sales sales_rep reads GlobalTech reports
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 2. Cross-org permission ---'

-- Judy is sales_rep at Sales. Add a cross-org rule:
-- Sales sales_rep can read GlobalTech reports
INSERT INTO morbac.cross_org_rules
    (source_org_id, target_org_id, role_id, activity, view, context_id, modality)
VALUES (
    '10000000-0000-0000-0000-000000000003', -- source: Sales Dept
    '10000000-0000-0000-0000-000000000001', -- target: GlobalTech HQ
    '20000000-0003-0000-0000-000000000002', -- sales_rep role
    'read', 'reports',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'permission'
);

-- Cross-org rule grants access
SELECT morbac.t('Judy (Sales sales_rep) reads GlobalTech reports via cross-org rule',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000010'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'reports'
    ), TRUE);

-- Judy at Sales can still read Sales docs normally (local rule, no cross-org needed)
SELECT morbac.t('Judy (Sales sales_rep) reads Sales documents [local rule]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000010'::uuid,
        '10000000-0000-0000-0000-000000000003'::uuid,
        'read', 'documents'
    ), TRUE);

-- Judy does NOT have permission to read GlobalTech documents (cross-org rule only covers reports)
SELECT morbac.t('Judy (Sales sales_rep) reads GlobalTech documents [no rule for documents]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000010'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'documents'
    ), FALSE);

-- ---------------------------------------------------------------------------
-- Section 3: User must hold role in source org
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 3. Role must be held in source org ---'

-- Karl has no role anywhere — cannot use the Sales->GlobalTech cross-org rule
SELECT morbac.t('Karl (no role) reads GlobalTech reports via cross-org rule [no role in source]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'reports'
    ), FALSE);

-- Karl also has no access to GlobalTech documents
SELECT morbac.t('Karl (no role) reads GlobalTech documents [no access anywhere]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000011'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'documents'
    ), FALSE);

-- ---------------------------------------------------------------------------
-- Section 4: Cross-org prohibition — blocks access even with regular permission
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 4. Cross-org prohibition ---'

-- Engineering engineer can normally read Engineering documents (local perm)
SELECT morbac.t('Judy (Engineering engineer) reads Engineering documents [local perm]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000010'::uuid,
        '10000000-0000-0000-0000-000000000002'::uuid,
        'read', 'documents'
    ), TRUE);

-- Add Diana (sales_manager at Sales) for cross-org prohibition test
INSERT INTO morbac.user_roles (user_id, role_id, org_id) VALUES
    ('30000000-0000-0000-0000-000000000015', '20000000-0003-0000-0000-000000000001', '10000000-0000-0000-0000-000000000003');

-- Add cross-org prohibition: Sales sales_manager prohibited from writing Engineering documents
INSERT INTO morbac.cross_org_rules
    (source_org_id, target_org_id, role_id, activity, view, context_id, modality)
VALUES (
    '10000000-0000-0000-0000-000000000003', -- source: Sales Dept
    '10000000-0000-0000-0000-000000000002', -- target: Engineering Dept
    '20000000-0003-0000-0000-000000000001', -- sales_manager role
    'write', 'documents',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'prohibition'
);

-- Also give a cross-org permission that would otherwise allow the write
INSERT INTO morbac.cross_org_rules
    (source_org_id, target_org_id, role_id, activity, view, context_id, modality)
VALUES (
    '10000000-0000-0000-0000-000000000003', -- source: Sales Dept
    '10000000-0000-0000-0000-000000000002', -- target: Engineering Dept
    '20000000-0003-0000-0000-000000000001', -- sales_manager role
    'write', 'documents',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'permission'
);

-- Cross-org prohibition takes precedence over permission
SELECT morbac.t('Diana (Sales sales_manager) writes Engineering documents [cross-org prohibition wins]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000015'::uuid,
        '10000000-0000-0000-0000-000000000002'::uuid,
        'write', 'documents'
    ), FALSE);

-- Diana can read Engineering documents (no prohibition for read)
INSERT INTO morbac.cross_org_rules
    (source_org_id, target_org_id, role_id, activity, view, context_id, modality)
VALUES (
    '10000000-0000-0000-0000-000000000003', -- source: Sales Dept
    '10000000-0000-0000-0000-000000000002', -- target: Engineering Dept
    '20000000-0003-0000-0000-000000000001', -- sales_manager role
    'read', 'documents',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'permission'
);

-- No prohibition for read, permission applies
SELECT morbac.t('Diana (Sales sales_manager) reads Engineering documents [cross-org permission]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000015'::uuid,
        '10000000-0000-0000-0000-000000000002'::uuid,
        'read', 'documents'
    ), TRUE);

-- ---------------------------------------------------------------------------
-- Section 5: Cross-org + activity hierarchy
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 5. Cross-org with activity hierarchy ---'

-- The sales_rep cross-org rule grants 'read reports' in GlobalTech.
-- With activity hierarchy (write->read), requesting 'write reports' also matches
-- the 'read' rule (get_effective_activities('write') = {write, read}).
SELECT morbac.t('Judy (Sales sales_rep) writes GlobalTech reports via cross-org + activity hierarchy',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000010'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'write', 'reports'
    ), TRUE);

-- ---------------------------------------------------------------------------
-- Section 6: Cross-org + view hierarchy
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 6. Cross-org with view hierarchy ---'

-- Add a cross-org rule for 'read documents' (not financial_data directly)
-- With view hierarchy (financial_data->documents), 'read documents' cross-org rule
-- also covers 'read financial_data' requests
INSERT INTO morbac.cross_org_rules
    (source_org_id, target_org_id, role_id, activity, view, context_id, modality)
VALUES (
    '10000000-0000-0000-0000-000000000003', -- source: Sales Dept
    '10000000-0000-0000-0000-000000000001', -- target: GlobalTech HQ
    '20000000-0003-0000-0000-000000000002', -- sales_rep role
    'read', 'documents',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'permission'
);

-- get_effective_views('financial_data') = {financial_data, documents}
-- so 'read documents' cross-org rule covers 'read financial_data' request
SELECT morbac.t('Judy (Sales sales_rep) reads GlobalTech financial_data via cross-org + view hierarchy',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000010'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'financial_data'
    ), TRUE);

-- ---------------------------------------------------------------------------
-- Section 7: Temporal cross-org rule
-- ---------------------------------------------------------------------------
\echo ''
\echo '--- 7. Temporal cross-org rule ---'

-- Add a time-limited cross-org rule for eng_auditor to read GlobalTech audit_logs
INSERT INTO morbac.cross_org_rules
    (source_org_id, target_org_id, role_id, activity, view, context_id, modality, valid_from, valid_until)
VALUES (
    '10000000-0000-0000-0000-000000000002', -- source: Engineering
    '10000000-0000-0000-0000-000000000001', -- target: GlobalTech HQ
    '20000000-0002-0000-0000-000000000003', -- eng_auditor role
    'read', 'audit_logs',
    (SELECT id FROM morbac.contexts WHERE name = 'always'),
    'permission',
    now() - interval '1 hour',
    now() + interval '1 day'
);

-- Nina (Engineering eng_auditor) reads GlobalTech audit_logs within window
SELECT morbac.t('Nina (Engineering eng_auditor) reads GlobalTech audit_logs [temporal cross-org, active]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000014'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'audit_logs'
    ), TRUE);

-- Expire the cross-org rule
UPDATE morbac.cross_org_rules
SET valid_until = now() - interval '1 second'
WHERE source_org_id = '10000000-0000-0000-0000-000000000002'
  AND target_org_id = '10000000-0000-0000-0000-000000000001'
  AND role_id = '20000000-0002-0000-0000-000000000003'
  AND activity = 'read' AND view = 'audit_logs';

-- Temporal rule expired
SELECT morbac.t('Nina (Engineering eng_auditor) reads GlobalTech audit_logs [temporal cross-org, expired]',
    morbac.is_allowed_nocache(
        '30000000-0000-0000-0000-000000000014'::uuid,
        '10000000-0000-0000-0000-000000000001'::uuid,
        'read', 'audit_logs'
    ), FALSE);

\echo ''
\echo '=== Cross-Organization Rules Tests Completed ==='
