package com.sptg.common.security.interceptor;

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

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.util.PatternMatchUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.sptg.common.core.beans.UserBean;
import com.sptg.common.security.annotation.Security;
import com.sptg.common.security.enums.DataFormatEnum;
import com.sptg.common.security.exception.BodyAuthenticationException;
import com.sptg.common.security.exception.BodyAuthorizationException;
import com.sptg.common.security.exception.ViewAuthenticationException;
import com.sptg.common.security.exception.ViewAuthorizationException;
import com.sptg.common.security.service.SecurityServiceInterface;

/**
 * title: SecurityInterceptor
 * package: com.sptg.common.security.interceptor
 * description: 权限拦截器
 */
public class SecurityInterceptor<Account extends UserBean> extends HandlerInterceptorAdapter {

    private final SecurityServiceInterface<Account> securityServiceInterface;


    public SecurityInterceptor(SecurityServiceInterface<Account> securityServiceInterface){
        this.securityServiceInterface = securityServiceInterface;
    }

    /**
     * 功能描述: 预处理方法
     * @param request 请求信息
     * @param response 响应信息
     * @param handler 响应方法
     * @return boolean 是否拦截
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception{
        if (handler instanceof HandlerMethod){
            // 将handler强转为HandlerMethod
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            // 从方法处理器中获取出要调用的方法
            Method method = handlerMethod.getMethod();
            //  获取方法上的权限注解
            Security security = method.getAnnotation(Security.class);
            //  获取用户
            Account onLineUser = this.securityServiceInterface.getOnLineUser();
            //  判断是否需要校验登陆
            if (null != security){
                if (null == onLineUser){
                    //  认证失败
                    throw this.throwsErrorByIsBody(security, BodyAuthenticationException.class, ViewAuthenticationException.class);
                }
                //  判断是否需要校验权限
                if (security.token().length > 0){
                    //  获取用户的权限列表
                    List<String> tokenList = onLineUser.getTokenList();
                    //  权限校验
                    boolean result = tokenList.stream().anyMatch(x -> PatternMatchUtils.simpleMatch(security.token(), x));
                    if (!result){
                        //  授权失败
                        throw this.throwsErrorByIsBody(security,BodyAuthorizationException.class, ViewAuthorizationException.class);
                    }
                }
            }
            request.setAttribute("onLineUser",onLineUser);
        }
        return true;
    }

    /**
     * 功能描述: 根据接口返回值的类型抛出对应的异常
     * @param security 权限注解
     * @param bodyError 响应体（认证/授权）异常
     * @param viewError 页面（认证/授权）异常
     */
    private RuntimeException throwsErrorByIsBody(Security security,
                                     Class bodyError,
                                     Class viewError) throws Exception{
        //  判断接口返回值的类型是否为Json
        if (DataFormatEnum.JSON.equals(security.format())){
            return (RuntimeException) bodyError.newInstance();
        }else {
            return (RuntimeException) viewError.newInstance();
        }
    }

}
