package com.atlassian.bitbucket.mesh.spring;

import com.atlassian.bitbucket.mesh.annotation.RequiresRole;
import com.atlassian.bitbucket.mesh.auth.AuthorisationManager;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;

@Aspect
@Order(2)
public class AuthorisationAspect {

    private final AuthorisationManager authorisationManager;

    public AuthorisationAspect(AuthorisationManager authorisationManager) {
        this.authorisationManager = authorisationManager;
    }

    @Pointcut("@annotation(com.atlassian.bitbucket.mesh.annotation.RequiresRole)")
    public void requiresRoleMethod() {
    }

    @Pointcut("@within(com.atlassian.bitbucket.mesh.annotation.RequiresRole)")
    public void requiresRoleType() {
    }

    @Around(value = "requiresRoleMethod() || requiresRoleType()")
    public Object checkApplicationRole(ProceedingJoinPoint joinPoint) throws Throwable {
        RequiresRole requiresRole;
        if (joinPoint.getSignature() instanceof MethodSignature) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            requiresRole = signature.getMethod().getAnnotation(RequiresRole.class);
        } else {
            Class<?> clazz = joinPoint.getSignature().getDeclaringType();
            requiresRole = clazz.getAnnotation(RequiresRole.class);
        }
        if (requiresRole != null) {
            authorisationManager.checkHasRole(requiresRole.value(), joinPoint.getSignature().toString());
        }
        return joinPoint.proceed();
    }
}
