package com.bcxin.ins.filter;

import com.alibaba.fastjson.JSONObject;
import com.bcxin.ins.dto.oauth.AccessToken;
import com.bcxin.ins.service.oauth.OAuthService;
import com.bcxin.ins.spring.util.SpringContextHolder;
import com.bcxin.ins.util.GlobalResources;
import com.bcxin.ins.util.http.ParameterRequestWrapper;
import com.bcxin.ins.util.toolbox.StrUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * <b> 鉴权拦截器 </b>
 * @author ZXF
 * @create 2021/12/15 0015 16:48
 * @version
 * @注意事项 </b>
 */
public class AccessControlFilter implements Filter {

    protected final Logger logger = LoggerFactory.getLogger(AccessControlFilter.class);

    @Override
    public void init(FilterConfig config) {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String spath = request.getServletPath();
        String path = request.getRequestURL().toString().split("\\?")[0];
        if(spath.startsWith("/static")
                ||spath.startsWith("/user/login")
                ||spath.startsWith("/servlet/validateCodeServlet")
                ||spath.startsWith("/admin")
                ||spath.startsWith("/resources")
                ||spath.startsWith("/weixin")
                ||path.endsWith(".css")
                ||path.endsWith(".js")
                ||path.endsWith(".png")
                ||path.endsWith(".jpg")
                ||path.endsWith(".pdf")
                ||path.endsWith(".gif")
                ||path.endsWith(".woff2")
                ||path.endsWith(".ico")){
            filterChain.doFilter(request, response);
            return;
        }
        logger.error("request url:"+request.getRequestURL().toString());
        logger.error("request Params:"+ JSONObject.toJSONString(request.getParameterMap()));
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers",
                "x-requested-with,content-type,Content-type,authorization,x-csrf-token,access_token");
        response.setHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8");
        //或捞地址后的token或捞请求头中携带的token
        String access_token = request.getParameter("ACCESS_TOKEN");
        if(StringUtils.isEmpty(access_token)){
            String referer_url = request.getHeader("Referer");
            if(StringUtils.isNotEmpty(referer_url)&&referer_url.contains("ACCESS_TOKEN=")&&!referer_url.endsWith("ACCESS_TOKEN=")){
                String x_at = referer_url.split("ACCESS_TOKEN=")[1];
                if(x_at.length()==32){
                    access_token = x_at;
                }else if(x_at.length()>32){
                    if(x_at.contains("&")){
                        x_at = x_at.split("&")[0];
                    }
                    if(x_at.length()>0){
                        access_token = x_at;
                    }
                }
            }
        }
        logger.error("request access_token:"+access_token);
        /*
            1.检查是否存在token
            2.token是否有对标用户信息
            3.如果有信息就将部分信息加入到request.setAttribute
            4.如果有携带token但无对标信息就强制跳到登录页
            5.不符合上述条件就跳过往下走，进入地址是否需要鉴权判断
        */
        AccessToken accessToken = null;
        if (StringUtils.isNotEmpty(access_token)) {
            OAuthService oAuthService = SpringContextHolder.getBean(OAuthService.class);
            if (oAuthService != null) {
                accessToken = oAuthService.getAccessToken(access_token);
                if (accessToken != null) {
                    request.setAttribute("create_by", accessToken.getUserId());
                    request.setAttribute("update_by", accessToken.getUserId());
                    request.setAttribute("webId", accessToken.getWebId());

                    Map<String, Object> paramter = new HashMap<String, Object>();

                    if(StrUtil.isEmpty(request.getParameter("webId"))){
                        paramter.put("webId", accessToken.getWebId());
                    }
                    paramter.put("create_by", accessToken.getUserId());
                    paramter.put("update_by", accessToken.getUserId());
                    paramter.put("ACCESS_TOKEN", access_token);

                    ParameterRequestWrapper wrapper = new ParameterRequestWrapper(request, paramter);
                    filterChain.doFilter(wrapper, response);
                    return;
                } else {
                    if(request.getServletPath().startsWith("/api/thr")
                            ||request.getServletPath().startsWith("/api/preservation")
                            ||request.getServletPath().startsWith("/app/report")){
                        //符合这3种类型的请求放行（提供给第三方的对接接口地址）
                    }else{
                        //只要有带token但是redis没找到的都默认跳登录页重新登录，不管它是否属于忽略对象
                        response.sendRedirect(GlobalResources.BASE_URL + "/user/login");
                        return;
                    }
                    /*ResultDto resultDto = new ResultDto("用户登陆超时或者未登陆", ConstProp.CODE_TOKEN_EXPIRED);
                    ObjectMapper mapper = new ObjectMapper();
                    PrintWriter out = response.getWriter();
                    out.print(mapper.writeValueAsString(resultDto));
                    out.close();
                    return;*/
                }
            }
        }/*else{
            ResultDto resultDto = new ResultDto("access_token缺失", ConstProp.CODE_TOKEN_EXPIRED);
            ObjectMapper mapper = new ObjectMapper();
            PrintWriter out = response.getWriter();
            out.print(mapper.writeValueAsString(resultDto));
            out.close();
            return;
        }*/
        /*
           1.定义需要忽略的请求地址前半截
           2.当前地址与定义的忽略地址配对
           3.配对上的表示当前地址不需要鉴权直接往下走
           4.配对不上的表示该地址需要登录才能访问，强制跳转到登录页
        */
        if(!decide(request.getServletPath())){
            //不在忽略范围内，需要鉴权的统一跳到登录页
            response.sendRedirect(GlobalResources.BASE_URL + "/user/login");
            return;
        }
        filterChain.doFilter(request, response);
    }

    /**
     * <b> 排除需要忽略鉴权的地址 （不做鉴权的地址往下列数组中加就行）</b>
     * 如果匹配到就返回true,表示当前访问地址为忽略对象
     * @author ZXF
     * @create 2021/12/15 0015 14:55
     * @version
     * @注意事项 </b>
     */
    private boolean decide(String path){
        String[] ignorePath = {"/test"
                ,"/synopsis"
                ,"/admin"
                ,"/api"
                ,"/base64"
                ,"/dwz"
                ,"/file"
                ,"/getResource"
                ,"/static"
                ,"/inform"
                ,"/infoNews"
                ,"/news"
                ,"/CA-API"
                ,"/QH-API"
                ,"/TB-API"
                ,"/user/login"
                ,"/PAC-API"
                ,"/RB-API"
                ,"/ZH-API"
                ,"/HT-API"
                ,"/TBAPI/GYX/syntony-service"
                ,"/insurance/gzzrx/transaction/syntony-service"
                ,"/insurance/gzzrx/transaction/syntony-service-record"
                ,"/insurance/gyx/transaction/syntony-service"
                ,"/insurance/gzx/transaction/syntony-service"
                ,"/transaction"
                ,"/insurance/tyx/transaction/syntony-service"
                ,"/insurance/zzx/transaction/syntony-service"
                ,"/insurance/build/product"
                ,"/insurance/gyx/product"
                ,"/insurance/gzx/product"
                ,"/insurance/gzzrx/product"
                ,"/insurance/lawsuit/product"
                ,"/insurance/gmr/product"
                ,"/insurance/customs/product"
                ,"/insurance/lote/product"
                ,"/insurance/gzzrx/policy/natureChange"
                ,"/weixin"
                ,"/insuranceService"
                ,"/policies_1"
                ,"/policies_2"
                ,"/policies_3"
                ,"/policies_4"
                ,"/footer_partners"
                ,"/footer_blogroll"
                ,"/config"
                ,"/getIframeUrl"
                ,"/user"
                ,"/app"
                ,"/resources"
                ,"/favicon.ico"
                ,"/pc/order/exportDetailByOrderID"
                ,"/insurance/product"};
        if(path.equals("/")){
            return true;
        }
        for (String str : ignorePath){
            if(path.startsWith(str)){
                //匹配到表示当前访问地址为忽略对象
                return true;
            }
        }
        //不在忽略范围
        return false;
    }

    @Override
    public void destroy() {

    }
}
