package com.yaoyuan.jiscuss.handler;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import java.util.Collection;

/**
 * RBAC (Role-Based Access Control) permission evaluator.
 *
 * <p>Rules:
 * <ul>
 *   <li>Anonymous / unauthenticated: denied</li>
 *   <li>ROLE_ADMIN: full access (all paths)</li>
 *   <li>ROLE_USER: access to all non-admin paths</li>
 *   <li>Admin-only paths ({@code /admin/**}, {@code /druid/**}, etc.) require ROLE_ADMIN</li>
 * </ul>
 *
 * <p>Previously this method unconditionally returned {@code true}, giving every user
 * unrestricted access regardless of role — a critical security vulnerability now fixed.
 */
@Component("rbacPermission")
public class RbacPermission {

    private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    /** URL patterns that require ROLE_ADMIN. */
    private static final String[] ADMIN_ONLY_PATTERNS = {
            "/admin/**",
            "/druid/**",
            "/actuator/**",
            "/h2-console/**",
            "/user_api/**",
            "/other_api/**"
    };

    /**
     * Evaluates whether the authenticated principal is permitted to access the requested URL.
     *
     * @param request        the current HTTP request
     * @param authentication the current authentication token
     * @return {@code true} when access is granted
     */
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        if (authentication == null
                || !authentication.isAuthenticated()
                || "anonymousUser".equals(authentication.getPrincipal())) {
            return false;
        }

        String uri = request.getRequestURI();
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();

        boolean isAdmin = authorities.stream()
                .anyMatch(a -> "ROLE_ADMIN".equals(a.getAuthority()));

        // Admin-only paths: only ROLE_ADMIN may proceed
        for (String pattern : ADMIN_ONLY_PATTERNS) {
            if (PATH_MATCHER.match(pattern, uri)) {
                return isAdmin;
            }
        }

        // All other paths are accessible by any authenticated user
        return true;
    }
}
