package com.changfa.config.shiro;

import com.alibaba.fastjson.JSON;
import com.changfa.annotations.GuestAccess;
import com.changfa.constants.ApiResult;
import com.changfa.enums.StatusEnum;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.UserFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.support.RequestContextUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.annotation.Annotation;

/**
 * @author:wwz
 **/
@Component
public class ShiroLoginFilter extends UserFilter {

    @Override
    protected void redirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().print(JSON.toJSON(ApiResult.error(StatusEnum.NOT_AUTH)));
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (isLoginRequest(request, response)) {
            return true;
        } else {
            HttpServletRequest servletRequest = WebUtils.toHttp(request);
            if(isAllowed(servletRequest)){
                return true;
            }
            Subject subject = getSubject(request, response);
            // If principal is not null, then the user is known and should be allowed access.
            return subject.getPrincipal() != null;
        }
    }

    private boolean isAllowed(HttpServletRequest request) {
        WebApplicationContext ctx = RequestContextUtils.findWebApplicationContext(request);
        RequestMappingHandlerMapping mapping = ctx.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class);
        HandlerExecutionChain handler = null;
        try {
            handler = mapping.getHandler(request);
            if(handler == null){
                return false;
            }
            Annotation[] declaredAnnotations = ((HandlerMethod) handler.getHandler()).
                    getMethod().getDeclaredAnnotations();
            for (Annotation annotation : declaredAnnotations) {
                /**
                 *如果含有@GuestAccess注解，则认为是不需要验证是否登录，
                 *直接放行即可
                 **/
                if (GuestAccess.class.equals(annotation.annotationType())) {
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


    public void saveRequestAndRedirectToLogin(ServletRequest request, ServletResponse response) throws IOException {
       // saveRequest(request);
        redirectToLogin(request, response);
    }
}
