-- ============================================================================
-- RBAC Schema: Role Permissions Table
-- Maps permissions to roles
-- ============================================================================

-- ============================================================================
-- ROLE_PERMISSIONS TABLE
-- Junction table linking roles to their permissions
-- ============================================================================

CREATE TABLE IF NOT EXISTS rbac.role_permissions (
    -- Primary key
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

    -- Role reference
    role_id UUID NOT NULL REFERENCES rbac.roles(id) ON DELETE CASCADE,

    -- Permission reference
    permission_id UUID NOT NULL REFERENCES rbac.permissions(id) ON DELETE CASCADE,

    -- Grant type: allow or deny (for permission inheritance override)
    grant_type VARCHAR(10) NOT NULL DEFAULT 'allow'
        CHECK (grant_type IN ('allow', 'deny')),

    -- Conditions for permission (JSON for field-level or conditional access)
    conditions JSONB DEFAULT NULL,

    -- Audit fields
    created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
    created_by UUID REFERENCES users.users(id),

    -- Constraints
    CONSTRAINT uq_role_permission UNIQUE (role_id, permission_id)
);

-- ============================================================================
-- INDEXES
-- ============================================================================

CREATE INDEX IF NOT EXISTS idx_role_permissions_role_id ON rbac.role_permissions(role_id);
CREATE INDEX IF NOT EXISTS idx_role_permissions_permission_id ON rbac.role_permissions(permission_id);
CREATE INDEX IF NOT EXISTS idx_role_permissions_grant_type ON rbac.role_permissions(grant_type);

-- ============================================================================
-- FUNCTION: Assign default permissions to system roles
-- ============================================================================

CREATE OR REPLACE FUNCTION rbac.assign_default_role_permissions(p_tenant_id UUID)
RETURNS void AS $$
DECLARE
    v_owner_role_id UUID;
    v_admin_role_id UUID;
    v_manager_role_id UUID;
    v_member_role_id UUID;
    v_viewer_role_id UUID;
    v_perm RECORD;
BEGIN
    -- Get role IDs
    SELECT id INTO v_owner_role_id FROM rbac.roles WHERE tenant_id = p_tenant_id AND slug = 'owner';
    SELECT id INTO v_admin_role_id FROM rbac.roles WHERE tenant_id = p_tenant_id AND slug = 'admin';
    SELECT id INTO v_manager_role_id FROM rbac.roles WHERE tenant_id = p_tenant_id AND slug = 'manager';
    SELECT id INTO v_member_role_id FROM rbac.roles WHERE tenant_id = p_tenant_id AND slug = 'member';
    SELECT id INTO v_viewer_role_id FROM rbac.roles WHERE tenant_id = p_tenant_id AND slug = 'viewer';

    -- Owner gets ALL permissions
    FOR v_perm IN SELECT id FROM rbac.permissions WHERE is_active = true
    LOOP
        INSERT INTO rbac.role_permissions (role_id, permission_id)
        VALUES (v_owner_role_id, v_perm.id)
        ON CONFLICT (role_id, permission_id) DO NOTHING;
    END LOOP;

    -- Admin gets all except org:delete and org:billing:manage
    FOR v_perm IN
        SELECT id FROM rbac.permissions
        WHERE is_active = true
        AND code NOT IN ('org:delete', 'org:billing:manage')
    LOOP
        INSERT INTO rbac.role_permissions (role_id, permission_id)
        VALUES (v_admin_role_id, v_perm.id)
        ON CONFLICT (role_id, permission_id) DO NOTHING;
    END LOOP;

    -- Manager gets user viewing, role viewing, and standard features
    FOR v_perm IN
        SELECT id FROM rbac.permissions
        WHERE is_active = true
        AND code IN (
            'org:read',
            'users:read', 'users:invite',
            'roles:read',
            'wallet:read', 'wallet:deposit', 'wallet:withdraw',
            'products:read', 'products:purchase',
            'vip:read', 'vip:subscribe',
            'agents:read', 'agents:allocate',
            'predictions:read', 'predictions:purchase',
            'reports:read'
        )
    LOOP
        INSERT INTO rbac.role_permissions (role_id, permission_id)
        VALUES (v_manager_role_id, v_perm.id)
        ON CONFLICT (role_id, permission_id) DO NOTHING;
    END LOOP;

    -- Member gets standard user features
    FOR v_perm IN
        SELECT id FROM rbac.permissions
        WHERE is_active = true
        AND code IN (
            'org:read',
            'wallet:read', 'wallet:deposit', 'wallet:withdraw',
            'products:read', 'products:purchase',
            'vip:read', 'vip:subscribe',
            'agents:read', 'agents:allocate',
            'predictions:read', 'predictions:purchase'
        )
    LOOP
        INSERT INTO rbac.role_permissions (role_id, permission_id)
        VALUES (v_member_role_id, v_perm.id)
        ON CONFLICT (role_id, permission_id) DO NOTHING;
    END LOOP;

    -- Viewer gets read-only access
    FOR v_perm IN
        SELECT id FROM rbac.permissions
        WHERE is_active = true
        AND code IN (
            'org:read',
            'wallet:read',
            'products:read',
            'vip:read',
            'agents:read',
            'predictions:read'
        )
    LOOP
        INSERT INTO rbac.role_permissions (role_id, permission_id)
        VALUES (v_viewer_role_id, v_perm.id)
        ON CONFLICT (role_id, permission_id) DO NOTHING;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

-- ============================================================================
-- VIEW: Role with permissions
-- ============================================================================

CREATE OR REPLACE VIEW rbac.v_role_permissions AS
SELECT
    r.id AS role_id,
    r.tenant_id,
    r.name AS role_name,
    r.slug AS role_slug,
    r.hierarchy_level,
    p.id AS permission_id,
    p.code AS permission_code,
    p.name AS permission_name,
    p.module,
    p.action,
    p.resource,
    rp.grant_type,
    rp.conditions
FROM rbac.roles r
JOIN rbac.role_permissions rp ON r.id = rp.role_id
JOIN rbac.permissions p ON rp.permission_id = p.id
WHERE r.is_active = true AND p.is_active = true;

-- ============================================================================
-- GRANTS
-- ============================================================================

GRANT SELECT, INSERT, DELETE ON rbac.role_permissions TO trading_user;
GRANT SELECT ON rbac.v_role_permissions TO trading_user;

-- ============================================================================
-- COMMENTS
-- ============================================================================

COMMENT ON TABLE rbac.role_permissions IS 'Junction table mapping permissions to roles';
COMMENT ON COLUMN rbac.role_permissions.grant_type IS 'allow = grants permission, deny = explicitly denies (for override)';
COMMENT ON COLUMN rbac.role_permissions.conditions IS 'JSON conditions for field-level or conditional access control';
