package org.springblade.common.auth.permission;

import org.springblade.common.auth.config.SpringCasAutoconfig;
import com.wn.common.controller.BaseController;
import java.io.IOException;
import java.util.Map;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.validation.Assertion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;

/**
 * @author caiyihua
 */
public class CasLoginCheckFilter implements Filter {
    private ApplicationContext context;
    private SpringCasAutoconfig autoconfig;
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    public void setAutoconfig(SpringCasAutoconfig autoconfig) {
        this.autoconfig = autoconfig;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        context = WebApplicationContextUtils.getWebApplicationContext(filterConfig.getServletContext());
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);

        Map requestParams = request.getParameterMap();
        String ignoreFilters = autoconfig.getIgnoreFilters();
        Pattern pattern = Pattern.compile(ignoreFilters);
        String url = request.getRequestURI();

        HandlerMethod handlerMethod = getHandlerMethod(request);
        if (pattern.matcher(url).find() || handlerMethod == null || !(handlerMethod.getBean() instanceof BaseController)
                || handlerMethod.hasMethodAnnotation(DisableLoginVerify.class)) {
            logger.debug("URL {} 不校验CAS登录，继续下一步...", request.getServletPath());
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            if ((requestParams.size() > 0 && requestParams.get("ticket") != null && StringUtils
                    .isNotEmpty(requestParams.get("ticket").toString())) || assertion != null) {
                logger.debug("URL {} 已经CAS登录成功，继续下一步...", request.getServletPath());
                filterChain.doFilter(servletRequest, servletResponse);
            } else {
                response.sendRedirect(
                        autoconfig.getRedirectToCasLogin() + "?currentPath=" + autoconfig.getServerName() + url);
            }
        }
    }

    private HandlerMethod getHandlerMethod(HttpServletRequest request) {
        Map<String, HandlerMapping> requestMappings = BeanFactoryUtils
                .beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        try {
            for (HandlerMapping handlerMapping : requestMappings.values()) {
                HandlerExecutionChain handlerExecutionChain = handlerMapping.getHandler(request);
                if (handlerExecutionChain != null && handlerExecutionChain.getHandler() instanceof HandlerMethod) {
                    return (HandlerMethod) handlerExecutionChain.getHandler();
                }
            }
        } catch (Exception e) {
            logger.error("获取URL{}对应的处理方法出现异常：{}", request.getServletPath(), e);
        }

        return null;
    }

    @Override
    public void destroy() {

    }
}
