package thyyxxk.webserver.aop.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import thyyxxk.webserver.aop.interfaces.NeedMenu;
import thyyxxk.webserver.config.auth.PassToken;
import thyyxxk.webserver.config.exception.BizException;
import thyyxxk.webserver.config.exception.ExceptionEnum;
import thyyxxk.webserver.entity.login.UserInfo;
import thyyxxk.webserver.enums.authorize.MenuEnum;
import thyyxxk.webserver.enums.authorize.RuleId;
import thyyxxk.webserver.service.hutoolcache.UserCache;
import thyyxxk.webserver.service.settings.MenuSettingsService;

import java.lang.reflect.Method;
import java.util.Set;


/**
 * @author 肖蟾
 */
@Aspect
@Component
@Slf4j
public class NeedMenuAop {
    private final MenuSettingsService menu;
    private final UserCache userCache;

    @Autowired
    public NeedMenuAop(MenuSettingsService menu, UserCache userCache) {
        this.menu = menu;
        this.userCache = userCache;
    }

    @Pointcut("execution(* thyyxxk.webserver..*(..))")
    public void Pointcut() {
    }

    /**
     * 如果这里不这样写就无法获取 注解里面的值
     *
     * @param noNeedRule
     */
    @Before(value = "Pointcut() && (@annotation(noNeedRule))", argNames = "pjp,noNeedRule")
    public void beforeMethod(JoinPoint pjp, NeedMenu noNeedRule) {
        // 获取切入的 Method
        MethodSignature joinPointObject = (MethodSignature) pjp.getSignature();
        Method method = joinPointObject.getMethod();
        boolean annotationPresent = method.isAnnotationPresent(PassToken.class);
        if (annotationPresent)
            return;
        MenuEnum[] value = noNeedRule.value();
        RuleId[] ruleIds = noNeedRule.rule();

        if (!hasMenu(value)) {
            throw new BizException(ExceptionEnum.LOGICAL_ERROR, "您没有此接口的权限");
        }

        if (!hasRule(ruleIds)) {
            throw new BizException(ExceptionEnum.LOGICAL_ERROR, "您没有此接口的权限");
        }
    }

    public boolean hasRule(RuleId[] ruleIds) {
        if (ruleIds == null || ruleIds.length == 0) {
            return true;
        }
        UserInfo us = userCache.getUserInfoByToken();

        if (us == null || us.getRoles() == null || us.getRoles().isEmpty()) {
            return false;
        }

        for (RuleId id : ruleIds) {
            if (us.getRoles().contains(id.getId())) {
                return true;
            }
        }

        return false;
    }

    public boolean hasMenu(MenuEnum[] value) {
        if (value == null || value.length == 0) {
            return true;
        }
        Set<String> redisMenuByCodeListName = menu.getRedisMenuByCodeListName();

        for (MenuEnum menuEnum : value) {
            String menuName = menuEnum.toString();
            if (redisMenuByCodeListName.contains(menuName)) {
                return true;
            }
        }
        return false;
    }

}
