import database from "../../config/db";

export class PermissionService {
  // Check if user has permission
  static async hasPermission(userId: string, permissionName: string, resourceId?: string): Promise<boolean> {
    try {
      const result = await database.query(
        `SELECT has_permission($1, $2, $3) as has_permission`,
        [userId, permissionName, resourceId || null]
      );
      
      return result.rows[0]?.has_permission || false;
    } catch (error) {
      console.error("Error checking permission:", error);
      return false;
    }
  }
  
  // Get all user permissions
  static async getUserPermissions(userId: string): Promise<string[]> {
    try {
      const result = await database.query(
        `SELECT permission_name FROM get_user_permissions($1)`,
        [userId]
      );
      
      return result.rows.map((row: any) => row.permission_name);
    } catch (error) {
      console.error("Error getting user permissions:", error);
      return [];
    }
  }
  
  // Get user roles
  static async getUserRoles(userId: string): Promise<any[]> {
    try {
      const result = await database.query(
        `SELECT * FROM get_user_roles($1)`,
        [userId]
      );
      
      return result.rows;
    } catch (error) {
      console.error("Error getting user roles:", error);
      return [];
    }
  }
  
  // Check if user has role
  static async hasRole(userId: string, roleName: string): Promise<boolean> {
    try {
      const result = await database.query(
        `SELECT EXISTS(
          SELECT 1 
          FROM role_assignments ra
          INNER JOIN roles r ON ra.role_id = r.id
          WHERE ra.account_id = $1 
            AND ra.is_active = true
            AND (ra.expires_at IS NULL OR ra.expires_at > CURRENT_TIMESTAMP)
            AND r.name = $2
        ) as has_role`,
        [userId, roleName]
      );
      
      return result.rows[0]?.has_role || false;
    } catch (error) {
      console.error("Error checking role:", error);
      return false;
    }
  }
  
  // Get user's highest role level
  static async getUserLevel(userId: string): Promise<number> {
    try {
      const result = await database.query(
        `SELECT COALESCE(MAX(r.level), 0) as user_level
         FROM role_assignments ra
         INNER JOIN roles r ON ra.role_id = r.id
         WHERE ra.account_id = $1 
           AND ra.is_active = true
           AND (ra.expires_at IS NULL OR ra.expires_at > CURRENT_TIMESTAMP)`,
        [userId]
      );
      
      return parseInt(result.rows[0]?.user_level || '0');
    } catch (error) {
      console.error("Error getting user level:", error);
      return 0;
    }
  }
  
  // Check if user can access resource (owner or has permission)
  static async canAccessResource(
    userId: string,
    resourceType: string,
    resourceId: string,
    permissionName: string,
    ownerField: string = 'user_id'
  ): Promise<boolean> {
    try {
      // Check if user is owner
      let tableName = '';
      switch (resourceType) {
        case 'user':
          tableName = 'accounts';
          break;
        case 'company':
          tableName = 'accounts';
          break;
        case 'content':
          tableName = 'activities';
          break;
        default:
          tableName = resourceType + 's';
      }
      
      const ownerResult = await database.query(
        `SELECT ${ownerField} FROM ${tableName} WHERE id = $1`,
        [resourceId]
      );
      
      if (ownerResult.rows.length > 0 && ownerResult.rows[0][ownerField] === userId) {
        return true;
      }
      
      // Check permission
      return await this.hasPermission(userId, permissionName, resourceId);
    } catch (error) {
      console.error("Error checking resource access:", error);
      return false;
    }
  }
  
  // Assign role to user
  static async assignRole(
    targetUserId: string,
    roleName: string,
    assignedByUserId: string,
    isPrimary: boolean = false,
    expiresAt?: Date,
    reason?: string
  ): Promise<boolean> {
    try {
      const result = await database.query(
        `SELECT * FROM assign_role_to_user($1, $2, $3, $4, $5, $6)`,
        [targetUserId, roleName, assignedByUserId, isPrimary, expiresAt || null, reason || null]
      );
      
      const assignmentResult = result.rows[0]?.assign_role_to_user;
      return assignmentResult?.success || false;
    } catch (error) {
      console.error("Error assigning role:", error);
      return false;
    }
  }
  
  // Remove role from user
  static async removeRole(
    targetUserId: string,
    roleName: string,
    removedByUserId: string,
    reason?: string
  ): Promise<boolean> {
    try {
      const result = await database.query(
        `SELECT * FROM remove_role_from_user($1, $2, $3, $4)`,
        [targetUserId, roleName, removedByUserId, reason || null]
      );
      
      const removalResult = result.rows[0]?.remove_role_from_user;
      return removalResult?.success || false;
    } catch (error) {
      console.error("Error removing role:", error);
      return false;
    }
  }
}