-- ============================================================================
-- RBAC Schema: Roles Table
-- Role-Based Access Control for Trading Platform SaaS
-- ============================================================================

-- Create RBAC schema if not exists
CREATE SCHEMA IF NOT EXISTS rbac;

-- Grant usage
GRANT USAGE ON SCHEMA rbac TO trading_user;

-- ============================================================================
-- ROLES TABLE
-- Defines roles within a tenant organization
-- ============================================================================

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

    -- Tenant relationship (multi-tenancy)
    tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,

    -- Role information
    name VARCHAR(100) NOT NULL,
    slug VARCHAR(100) NOT NULL,
    description TEXT,

    -- Role type: system (predefined) or custom (tenant-created)
    role_type VARCHAR(20) NOT NULL DEFAULT 'custom'
        CHECK (role_type IN ('system', 'custom')),

    -- Hierarchy level (lower = more permissions, 0 = super admin)
    hierarchy_level INTEGER NOT NULL DEFAULT 100,

    -- Status
    is_active BOOLEAN NOT NULL DEFAULT true,

    -- Role settings (JSON for extensibility)
    settings JSONB NOT NULL DEFAULT '{}'::jsonb,

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

    -- Constraints
    CONSTRAINT uq_roles_tenant_slug UNIQUE (tenant_id, slug),
    CONSTRAINT uq_roles_tenant_name UNIQUE (tenant_id, name)
);

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

CREATE INDEX IF NOT EXISTS idx_roles_tenant_id ON rbac.roles(tenant_id);
CREATE INDEX IF NOT EXISTS idx_roles_slug ON rbac.roles(slug);
CREATE INDEX IF NOT EXISTS idx_roles_role_type ON rbac.roles(role_type);
CREATE INDEX IF NOT EXISTS idx_roles_is_active ON rbac.roles(is_active);
CREATE INDEX IF NOT EXISTS idx_roles_hierarchy ON rbac.roles(tenant_id, hierarchy_level);

-- ============================================================================
-- ROW LEVEL SECURITY
-- ============================================================================

ALTER TABLE rbac.roles ENABLE ROW LEVEL SECURITY;

-- Policy: Users can only see roles in their tenant
CREATE POLICY roles_tenant_isolation ON rbac.roles
    FOR ALL
    USING (tenant_id = current_setting('app.current_tenant_id', true)::uuid);

-- ============================================================================
-- TRIGGERS
-- ============================================================================

-- Auto-update updated_at timestamp
CREATE OR REPLACE FUNCTION rbac.update_roles_timestamp()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = CURRENT_TIMESTAMP;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_roles_updated_at
    BEFORE UPDATE ON rbac.roles
    FOR EACH ROW
    EXECUTE FUNCTION rbac.update_roles_timestamp();

-- ============================================================================
-- DEFAULT SYSTEM ROLES (inserted per tenant)
-- These will be created when a new tenant is created
-- ============================================================================

-- Function to create default roles for a tenant
CREATE OR REPLACE FUNCTION rbac.create_default_roles(p_tenant_id UUID, p_owner_id UUID)
RETURNS void AS $$
BEGIN
    -- Owner role (highest level)
    INSERT INTO rbac.roles (tenant_id, name, slug, description, role_type, hierarchy_level, created_by)
    VALUES (
        p_tenant_id,
        'Owner',
        'owner',
        'Full access to all features and settings. Can manage billing and delete organization.',
        'system',
        0,
        p_owner_id
    );

    -- Admin role
    INSERT INTO rbac.roles (tenant_id, name, slug, description, role_type, hierarchy_level, created_by)
    VALUES (
        p_tenant_id,
        'Admin',
        'admin',
        'Administrative access. Can manage users, roles, and most settings.',
        'system',
        10,
        p_owner_id
    );

    -- Manager role
    INSERT INTO rbac.roles (tenant_id, name, slug, description, role_type, hierarchy_level, created_by)
    VALUES (
        p_tenant_id,
        'Manager',
        'manager',
        'Can manage team members and view reports.',
        'system',
        50,
        p_owner_id
    );

    -- Member role
    INSERT INTO rbac.roles (tenant_id, name, slug, description, role_type, hierarchy_level, created_by)
    VALUES (
        p_tenant_id,
        'Member',
        'member',
        'Standard user access. Can use platform features.',
        'system',
        100,
        p_owner_id
    );

    -- Viewer role (read-only)
    INSERT INTO rbac.roles (tenant_id, name, slug, description, role_type, hierarchy_level, created_by)
    VALUES (
        p_tenant_id,
        'Viewer',
        'viewer',
        'Read-only access. Can view but not modify.',
        'system',
        200,
        p_owner_id
    );
END;
$$ LANGUAGE plpgsql;

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

GRANT SELECT, INSERT, UPDATE, DELETE ON rbac.roles TO trading_user;

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

COMMENT ON TABLE rbac.roles IS 'Roles for Role-Based Access Control within tenant organizations';
COMMENT ON COLUMN rbac.roles.role_type IS 'system = predefined roles, custom = tenant-created roles';
COMMENT ON COLUMN rbac.roles.hierarchy_level IS 'Lower value = higher permissions. Owner=0, Admin=10, etc.';
COMMENT ON COLUMN rbac.roles.settings IS 'JSON settings for role customization';
