/*
 * Copyright (c) 2023 codvision.com All Rights Reserved.
 */

package com.codvision.authcore.interceptor;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.codvision.authcore.annotation.RequiresPermissions;
import com.codvision.authcore.bean.SysMenuBean;
import com.codvision.authcore.bean.SysUserBean;
import com.codvision.authcore.config.AuthProperties;
import com.codvision.authcore.constants.AuthCoreConstant;
import com.codvision.authcore.service.IAuthService;
import com.codvision.authcore.util.RequestUtil;
import com.codvision.commoncore.exception.AuthException;
import com.codvision.commoncore.exception.PermissionException;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Optional;

/**
 * 认证拦截器
 *
 * @author lingee
 * @date 2023/8/3
 */
public class AuthInterceptor implements HandlerInterceptor {

    @Resource
    private AuthProperties authProperties;

    @Resource
    private IAuthService authService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        final String path = request.getServletPath();

        if (RequestUtil.isExcludedUri(path, authProperties.getExcludes())) {
            return true;
        }
        final String token = authService.getAuthToken(request);
        Optional.ofNullable(token).orElseThrow(() -> new AuthException(10002));

        SysUserBean sysUser = authService.getCurrentUserInfo(token);
        Optional.ofNullable(sysUser).orElseThrow(() -> new AuthException(10002));

        if (handler.getClass().isAssignableFrom(HandlerMethod.class)) {
            RequiresPermissions permissions = getRequiresPermissions((HandlerMethod) handler);
            if (ObjectUtil.isEmpty(permissions)) {
                return true;
            }
            String code = permissions.value();
            if (StrUtil.isNotBlank(code)) {
                Optional.ofNullable(sysUser.getActiveRoleId()).orElseThrow(() -> new PermissionException("当前用户无授权角色"));

                List<SysMenuBean> sysMenus = authService.getMenuList(token);
                if (CollectionUtils.isEmpty(sysMenus)) {
                    throw new PermissionException("当前用户无菜单权限");
                }
                if (sysMenus.stream().filter(x -> code.equals(x.getPermission())).count() == 0) {
                    throw new PermissionException("当前用户无访问权限");
                }
            }
        }
        return true;
    }

    /**
     * 获取hander上的RequiresPermissions注解
     *
     * @param handler 处理对象
     * @return 注解
     */
    private RequiresPermissions getRequiresPermissions(HandlerMethod handler) {
        RequiresPermissions requiresPermissions = handler.getMethodAnnotation(RequiresPermissions.class);
        if (ObjectUtils.isEmpty(requiresPermissions)) {
            requiresPermissions = AnnotatedElementUtils.getMergedAnnotation(handler.getBean().getClass(), RequiresPermissions.class);
        }
        return requiresPermissions;
    }
}
