package com.winsun.aop;

import com.alibaba.fastjson.JSONObject;
import com.winsun.auth.core.common.model.ResponseData;
import com.winsun.auth.core.shiro.ShiroUser;
import com.winsun.auth.core.support.HttpKit;
import com.winsun.auth.model.common.Menu;
import com.winsun.interfaces.PermissionVerification;
import com.winsun.mapper.SysUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 基于服务层的权限切面
 *
 * @author Cocowwy
 * @create 2021-11-11-13:59
 */
@Aspect
@Component
@Slf4j
public class AuthorityAspect {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private SysUserMapper sysUserMapper;

    private final static String PERMISSION_VERIFICATION = "permissionVerification:";

    private final static Integer CACHE_TIME =  60;

    /**
     * 对接口进行权限校验
     */
    @Pointcut("@annotation(com.winsun.interfaces.PermissionVerification)")
    private void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        PermissionVerification permissionVerification = signature.getMethod().getDeclaredAnnotation(PermissionVerification.class);
        if (permissionVerification != null) {
            return apiIdempotent(joinPoint, signature);
        }
        Object proceed = joinPoint.proceed();
        return proceed;
    }

    public Object apiIdempotent(ProceedingJoinPoint joinPoint, MethodSignature signature) throws Throwable {
        ShiroUser user = getShiroUser();
        /*if (user.getRoleNames().stream().anyMatch(roleName -> StringUtils.equalsAny(roleName, "超级管理员"))) {
            Object proceed = joinPoint.proceed();
            return proceed;
        }*/
        PermissionVerification permissionVerification = signature.getMethod().getDeclaredAnnotation(PermissionVerification.class);
        if ("".equals(permissionVerification.value()[0]) || user == null) {
            log.error("无权限");
            return false;
        }

        List<Integer> roleList = user.getRoleList();
        if (roleList.size() == 0) {
            log.error("无权限");
            return false;
        }

        String key = PERMISSION_VERIFICATION + getHttpServletRequest().getHeader("Authorization");
        String[] values = permissionVerification.value();

        String s = stringRedisTemplate.opsForValue().get(key);
        List<Menu> roleMenu = null;
        if (StringUtils.isNotBlank(s)) {
            roleMenu = JSONObject.parseArray(s, Menu.class);
        }else {
            roleMenu = sysUserMapper.getRoleMenu(roleList);
            stringRedisTemplate.opsForValue().set(key,
                    JSONObject.toJSONString(roleMenu),
                    CACHE_TIME, TimeUnit.SECONDS);
        }

        if (roleMenu == null || roleMenu.isEmpty()) {
            return false;
        }
        for (String value : values) {
            for (Menu menu : roleMenu) {
                if (menu == null || StringUtils.isBlank(menu.getUrl())) {
                    continue;
                }

                if (StringUtils.equals(menu.getUrl(), value)) {
                    Object proceed = joinPoint.proceed();
                    return proceed;
                }
            }

        }
        return ResponseData.error("无权限");
    }

    protected ShiroUser getShiroUser() {
        HttpServletRequest httpServletRequest = this.getHttpServletRequest();
        Object Attr = httpServletRequest.getAttribute("user");
        ShiroUser user = (ShiroUser) JSONObject.parseObject(Attr.toString(), ShiroUser.class);
        return user;
    }

    protected HttpServletRequest getHttpServletRequest() {
        return HttpKit.getRequest();
    }
}

