package com.saas.shared.security;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import java.io.Serializable;

/**
 * Custom PermissionEvaluator for advanced RBAC permission checks.
 * 
 * Enables fine-grained permission control in @PreAuthorize annotations:
 * @PreAuthorize("hasPermission('tenant', 'write')")
 * @PreAuthorize("hasPermission(#tenantId, 'Tenant', 'read')")
 * 
 * This evaluator checks if the authenticated user has the required permission
 * based on their assigned roles and permissions from the RBAC system.
 */
@Component
@Slf4j
public class CustomPermissionEvaluator implements PermissionEvaluator {
    
    /**
     * Check if user has permission on a domain object
     * 
     * Example: hasPermission(tenantId, 'Tenant', 'write')
     * 
     * @param authentication User authentication
     * @param targetDomainObject Target object (e.g., tenant ID)
     * @param permission Permission to check (e.g., "write")
     * @return true if user has permission
     */
    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
        if (authentication == null || permission == null) {
            return false;
        }
        
        // For now, delegate to hasPermission(resource, action) format
        // Can be extended for object-level permissions in future
        return hasSimplePermission(authentication, permission.toString());
    }
    
    /**
     * Check if user has permission on a target type
     * 
     * Example: hasPermission('tenant', 'Tenant', 'read')
     * Translates to checking for "tenant:read" permission
     * 
     * @param authentication User authentication
     * @param targetId Target ID (optional, can be used for data filtering)
     * @param targetType Resource type (e.g., "Tenant", "VoIP", "User")
     * @param permission Action permission (e.g., "read", "write", "delete")
     * @return true if user has permission
     */
    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        if (authentication == null || targetType == null || permission == null) {
            return false;
        }
        
        // Convert targetType to lowercase resource name
        String resource = targetType.toLowerCase();
        String action = permission.toString().toLowerCase();
        String requiredPermission = resource + ":" + action;
        
        return hasSimplePermission(authentication, requiredPermission);
    }
    
    /**
     * Check if user has a specific permission string
     * Format: "resource:action" (e.g., "tenant:read", "voip:write")
     */
    private boolean hasSimplePermission(Authentication authentication, String requiredPermission) {
        if (authentication == null || authentication.getAuthorities() == null) {
            return false;
        }
        
        // Check if user has the required permission in their granted authorities
        boolean hasPermission = authentication.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .anyMatch(auth -> auth.equals(requiredPermission));
        
        log.debug("🔐 Permission check: {} → {}", requiredPermission, hasPermission);
        
        return hasPermission;
    }
}
