"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.rbacService = exports.RBACService = exports.Permission = exports.UserRole = void 0;
const directus_client_1 = require("../../../scripts/utils/directus-client");
const jwt = __importStar(require("jsonwebtoken"));
// Import Directus SDK functions
const directusSdk = require('@directus/sdk');
const readMe = directusSdk.readMe;
const readRole = directusSdk.readRole;
const readRoles = directusSdk.readRoles;
const readPermissions = directusSdk.readPermissions;
const readItem = directusSdk.readItem;
/**
 * User Role Definitions
 */
var UserRole;
(function (UserRole) {
    UserRole["ADMIN"] = "admin";
    UserRole["TASK_MANAGER"] = "task_manager";
    UserRole["PROJECT_LEAD"] = "project_lead";
    UserRole["TEAM_MEMBER"] = "team_member";
    UserRole["VIEWER"] = "viewer";
})(UserRole || (exports.UserRole = UserRole = {}));
/**
 * Permission Types
 */
var Permission;
(function (Permission) {
    // Task permissions
    Permission["CREATE_TASK"] = "task.create";
    Permission["READ_TASK"] = "task.read";
    Permission["UPDATE_TASK"] = "task.update";
    Permission["DELETE_TASK"] = "task.delete";
    Permission["ASSIGN_TASK"] = "task.assign";
    // Project permissions
    Permission["CREATE_PROJECT"] = "project.create";
    Permission["READ_PROJECT"] = "project.read";
    Permission["UPDATE_PROJECT"] = "project.update";
    Permission["DELETE_PROJECT"] = "project.delete";
    Permission["MANAGE_PROJECT_MEMBERS"] = "project.manage_members";
    // User management permissions
    Permission["MANAGE_USERS"] = "user.manage";
    Permission["VIEW_USERS"] = "user.view";
    // Workflow permissions
    Permission["MANAGE_WORKFLOWS"] = "workflow.manage";
    Permission["TRIGGER_TRANSITIONS"] = "workflow.trigger";
    // Reporting permissions
    Permission["VIEW_REPORTS"] = "reports.view";
    Permission["EXPORT_REPORTS"] = "reports.export";
    // System permissions
    Permission["MANAGE_SYSTEM"] = "system.manage";
    Permission["VIEW_AUDIT_LOGS"] = "audit.view";
})(Permission || (exports.Permission = Permission = {}));
/**
 * Role-Permission Mapping
 */
const ROLE_PERMISSIONS = {
    [UserRole.ADMIN]: [
        // Admin has all permissions
        ...Object.values(Permission)
    ],
    [UserRole.TASK_MANAGER]: [
        Permission.CREATE_TASK,
        Permission.READ_TASK,
        Permission.UPDATE_TASK,
        Permission.DELETE_TASK,
        Permission.ASSIGN_TASK,
        Permission.CREATE_PROJECT,
        Permission.READ_PROJECT,
        Permission.UPDATE_PROJECT,
        Permission.MANAGE_PROJECT_MEMBERS,
        Permission.VIEW_USERS,
        Permission.MANAGE_WORKFLOWS,
        Permission.TRIGGER_TRANSITIONS,
        Permission.VIEW_REPORTS,
        Permission.EXPORT_REPORTS,
        Permission.VIEW_AUDIT_LOGS
    ],
    [UserRole.PROJECT_LEAD]: [
        Permission.CREATE_TASK,
        Permission.READ_TASK,
        Permission.UPDATE_TASK,
        Permission.ASSIGN_TASK,
        Permission.READ_PROJECT,
        Permission.UPDATE_PROJECT,
        Permission.MANAGE_PROJECT_MEMBERS,
        Permission.VIEW_USERS,
        Permission.TRIGGER_TRANSITIONS,
        Permission.VIEW_REPORTS,
        Permission.EXPORT_REPORTS
    ],
    [UserRole.TEAM_MEMBER]: [
        Permission.READ_TASK,
        Permission.UPDATE_TASK,
        Permission.READ_PROJECT,
        Permission.VIEW_USERS,
        Permission.VIEW_REPORTS
    ],
    [UserRole.VIEWER]: [
        Permission.READ_TASK,
        Permission.READ_PROJECT,
        Permission.VIEW_USERS,
        Permission.VIEW_REPORTS
    ]
};
/**
 * RBAC Service
 * Handles role-based access control and permission management
 */
class RBACService {
    constructor() {
        this.userCache = new Map();
        this.cacheTimeout = 5 * 60 * 1000; // 5 minutes
        this.initializeClient();
    }
    async initializeClient() {
        this.client = await (0, directus_client_1.getAuthenticatedClient)();
    }
    /**
     * Get user context with role and permissions
     */
    async getUserContext(userId) {
        // Check cache first
        const cached = this.userCache.get(userId);
        if (cached) {
            return cached;
        }
        if (!this.client)
            await this.initializeClient();
        try {
            // Fetch user with role information
            const user = await this.client.request(readItem('directus_users', userId, {
                fields: ['*', 'role.*']
            }));
            if (!user) {
                throw new Error('User not found');
            }
            // Map Directus role to our UserRole enum
            const userRole = this.mapDirectusRole(user.role);
            // Get permissions for the role
            const permissions = ROLE_PERMISSIONS[userRole] || [];
            // Get user's project and team assignments
            const projects = await this.getUserProjects(userId);
            const teams = await this.getUserTeams(userId);
            const context = {
                id: user.id,
                email: user.email,
                role: userRole,
                permissions,
                projects,
                teams
            };
            // Cache the context
            this.userCache.set(userId, context);
            setTimeout(() => this.userCache.delete(userId), this.cacheTimeout);
            return context;
        }
        catch (error) {
            throw new Error(`Failed to get user context: ${error.message}`);
        }
    }
    /**
     * Check if user has a specific permission
     */
    async hasPermission(userId, permission) {
        try {
            const context = await this.getUserContext(userId);
            return context.permissions.includes(permission);
        }
        catch (error) {
            console.error('Permission check failed:', error);
            return false;
        }
    }
    /**
     * Check if user has any of the specified permissions
     */
    async hasAnyPermission(userId, permissions) {
        try {
            const context = await this.getUserContext(userId);
            return permissions.some(permission => context.permissions.includes(permission));
        }
        catch (error) {
            console.error('Permission check failed:', error);
            return false;
        }
    }
    /**
     * Check if user has all of the specified permissions
     */
    async hasAllPermissions(userId, permissions) {
        try {
            const context = await this.getUserContext(userId);
            return permissions.every(permission => context.permissions.includes(permission));
        }
        catch (error) {
            console.error('Permission check failed:', error);
            return false;
        }
    }
    /**
     * Check if user can access a specific task
     */
    async canAccessTask(userId, taskId) {
        try {
            const context = await this.getUserContext(userId);
            // Admins and Task Managers can access all tasks
            if (context.role === UserRole.ADMIN || context.role === UserRole.TASK_MANAGER) {
                return true;
            }
            // Check if user has read permission
            if (!context.permissions.includes(Permission.READ_TASK)) {
                return false;
            }
            // Fetch the task to check ownership/assignment
            const task = await this.client.request(readItem('tasks', taskId, {
                fields: ['assigned_to', 'project', 'created_by']
            }));
            if (!task) {
                return false;
            }
            // Check if user is assigned to the task
            if (task.assigned_to === userId) {
                return true;
            }
            // Check if user is the creator
            if (task.created_by === userId) {
                return true;
            }
            // Check if user is a project lead for the task's project
            if (context.role === UserRole.PROJECT_LEAD &&
                context.projects?.includes(task.project)) {
                return true;
            }
            // Team members can see tasks in their projects
            if (context.role === UserRole.TEAM_MEMBER &&
                context.projects?.includes(task.project)) {
                return true;
            }
            return false;
        }
        catch (error) {
            console.error('Task access check failed:', error);
            return false;
        }
    }
    /**
     * Check if user can modify a specific task
     */
    async canModifyTask(userId, taskId) {
        try {
            const context = await this.getUserContext(userId);
            // Check update permission
            if (!context.permissions.includes(Permission.UPDATE_TASK)) {
                return false;
            }
            // Admins and Task Managers can modify all tasks
            if (context.role === UserRole.ADMIN || context.role === UserRole.TASK_MANAGER) {
                return true;
            }
            // Fetch the task
            const task = await this.client.request(readItem('tasks', taskId, {
                fields: ['assigned_to', 'project', 'created_by']
            }));
            if (!task) {
                return false;
            }
            // Project leads can modify tasks in their projects
            if (context.role === UserRole.PROJECT_LEAD &&
                context.projects?.includes(task.project)) {
                return true;
            }
            // Team members can only modify tasks assigned to them
            if (context.role === UserRole.TEAM_MEMBER &&
                task.assigned_to === userId) {
                return true;
            }
            return false;
        }
        catch (error) {
            console.error('Task modify check failed:', error);
            return false;
        }
    }
    /**
     * Verify JWT token and return user ID
     */
    async verifyToken(token) {
        try {
            const decoded = jwt.verify(token, process.env.JWT_SECRET || 'your-secret-key');
            return decoded.userId || null;
        }
        catch (error) {
            return null;
        }
    }
    /**
     * Check if user can assign tasks
     */
    async canAssignTasks(userId, projectId) {
        try {
            const context = await this.getUserContext(userId);
            // Check assign permission
            if (!context.permissions.includes(Permission.ASSIGN_TASK)) {
                return false;
            }
            // Admins and Task Managers can assign any tasks
            if (context.role === UserRole.ADMIN || context.role === UserRole.TASK_MANAGER) {
                return true;
            }
            // Project leads can assign tasks in their projects
            if (context.role === UserRole.PROJECT_LEAD) {
                if (!projectId) {
                    return !!(context.projects && context.projects.length > 0);
                }
                return context.projects?.includes(projectId) || false;
            }
            return false;
        }
        catch (error) {
            console.error('Task assignment check failed:', error);
            return false;
        }
    }
    /**
     * Get tasks accessible to a user
     */
    async getAccessibleTasks(userId) {
        try {
            const context = await this.getUserContext(userId);
            // Build filter based on role
            let filter = {};
            switch (context.role) {
                case UserRole.ADMIN:
                case UserRole.TASK_MANAGER:
                    // No filter - can see all tasks
                    break;
                case UserRole.PROJECT_LEAD:
                    // Can see tasks in their projects
                    if (context.projects && context.projects.length > 0) {
                        filter.project = { _in: context.projects };
                    }
                    else {
                        filter.id = { _eq: 'none' }; // No access
                    }
                    break;
                case UserRole.TEAM_MEMBER:
                    // Can see assigned tasks and tasks in their projects
                    filter._or = [
                        { assigned_to: { _eq: userId } },
                        { project: { _in: context.projects || [] } }
                    ];
                    break;
                case UserRole.VIEWER:
                    // Can see tasks in their projects (read-only)
                    if (context.projects && context.projects.length > 0) {
                        filter.project = { _in: context.projects };
                    }
                    else {
                        filter.id = { _eq: 'none' }; // No access
                    }
                    break;
                default:
                    filter.id = { _eq: 'none' }; // No access
            }
            return filter;
        }
        catch (error) {
            console.error('Failed to get accessible tasks filter:', error);
            return { id: { _eq: 'none' } };
        }
    }
    /**
     * Map Directus role to UserRole enum
     */
    mapDirectusRole(directusRole) {
        if (!directusRole || !directusRole.name) {
            return UserRole.VIEWER;
        }
        const roleName = directusRole.name.toLowerCase();
        if (roleName.includes('admin')) {
            return UserRole.ADMIN;
        }
        if (roleName.includes('manager')) {
            return UserRole.TASK_MANAGER;
        }
        if (roleName.includes('lead')) {
            return UserRole.PROJECT_LEAD;
        }
        if (roleName.includes('member') || roleName.includes('developer')) {
            return UserRole.TEAM_MEMBER;
        }
        return UserRole.VIEWER;
    }
    /**
     * Get user's projects
     */
    async getUserProjects(userId) {
        if (!this.client)
            await this.initializeClient();
        try {
            // This would query a project_members table or similar
            // For now, returning empty array
            return [];
        }
        catch (error) {
            console.error('Failed to get user projects:', error);
            return [];
        }
    }
    /**
     * Get user's teams
     */
    async getUserTeams(userId) {
        if (!this.client)
            await this.initializeClient();
        try {
            // This would query a team_members table or similar
            // For now, returning empty array
            return [];
        }
        catch (error) {
            console.error('Failed to get user teams:', error);
            return [];
        }
    }
    /**
     * Clear user cache
     */
    clearUserCache(userId) {
        if (userId) {
            this.userCache.delete(userId);
        }
        else {
            this.userCache.clear();
        }
    }
    /**
     * Get all available roles
     */
    async getAllRoles() {
        if (!this.client)
            await this.initializeClient();
        try {
            const roles = await this.client.request(readRoles());
            return roles;
        }
        catch (error) {
            throw new Error(`Failed to get roles: ${error.message}`);
        }
    }
    /**
     * Get permissions for a role
     */
    getPermissionsForRole(role) {
        return ROLE_PERMISSIONS[role] || [];
    }
}
exports.RBACService = RBACService;
// Export singleton instance
exports.rbacService = new RBACService();
//# sourceMappingURL=rbac.service.js.map