package demojsoncrud.servlets;

import demojsoncrud.utilities.GeneralUtils;
import demojsoncrud.utilities.PostRequest;
import demojsoncrud.utilities.VistasExtras;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import org.json.JSONArray;
import org.json.JSONObject;

@WebFilter("/*")
public class RequestFilter implements Filter, ServletContextListener {
    private final String BASE = "http://localhost:8080/proyecto-estandar/";//Modificar con la ruta de su proyecto
    private final String BASE_IP = "http://172.16.2.53:8080/proyecto-estandar/";
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }
    /**
     * <p>
     * BASE = Es la ruta del proyecto que se va implementar esta es la variable que se va a modificar en primera instancia. 
     * urlRequested = a la ruta para la verificación del token de la API REST. 
     * login = a la pantalla de inicio del sistema en este caso el login.
     * js = a la ruta /nombre_de_proyecto/js esto sirve para darle acceso a todos los archivos que se encuentren en la carpeta js sin necesidad de validar el token
     * css = a la ruta /nombre_de_proyecto/css esto sirve para darle acceso a todos los archivos que se encuentren en la carpeta css sin necesidad de validar el token
     * postRequest = new PostRequest(urlRequested); urlRequested es la ruta que se va enviar para poder enviar una peticion post al servidor para validar el TOKEN
     * JSONObject valid = va capturar la respuesta de la petición post al servidor una respuesta importante es su status=true: su token fue verificado correctamente, status=false: su token fue rechazado y se le enviar una excepción UNAUTHORIZED
     * </p>
     * @param req recibe el parametro para poder asignar su valor a HttpServletResponse response para obtener los métodos básicos de un servlet 
     * @param res recibe el parametro para poder asignar su valor a HttpServletRequest request para obtener los métodos básicos de un servlet
     * @param chain se utiliza (chain.doFilter(request, response);) para pasar el acceso al siguiente filtro sí existieran mas filtros y sí no hay mas filtros te redirecciona a el servlet solicitado.
     * @throws IOException
     * @throws ServletException 
     */
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        String respuesta = "";
        String urlRequested = "http://172.16.2.53:8080/security-rest/api/user/verificarLogin";
        System.out.println("URI "+request.getRequestURI());
//        if (String.valueOf(request.getRequestURL()).contains(BASE)||String.valueOf(request.getRequestURL()).contains(BASE_IP)) {
            String login = request.getContextPath() + "/vistas/index.jsp";
            String plantilla = request.getContextPath() + "/plantilla";
            String js = request.getContextPath() + "/js";
            String css = request.getContextPath() + "/css";
            System.out.println(js);
            String url = String.valueOf(request.getRequestURL());
            System.out.println("URI   _"+request.getRequestURI());
            System.out.println("URL _ "+url);
            /*Colocar sus recursos*/
            if (url.equalsIgnoreCase(BASE) || url.contains(login) || url.contains(plantilla) || url.contains(js)|| url.contains(css)|| url.contains("index.jsp")//||url.contains("main.jsp")
                    ||url.contains(".png")||url.contains(".jpg")|| url.contains("RedireccionarServlet")||url.contains("vistas/logout")) {
                chain.doFilter(request, response);
            } else {
                PostRequest postRequest = new PostRequest(urlRequested);
                JSONObject valid = null;
                String auth = "";
                if(url.contains(".jsp")){/*Valida la redirección entre páginas obteniendo los cookies y capturando el token */
                    auth = request.getHeader("Cookie"); 
                    if(auth!=null){
                        if(auth.contains("Bearer")){
                            int indiceBearer = 0;
                            int indiceToken = 0;
                            String[] parts = auth.split(";");

                            for (int i = 0; i < parts.length-1; i++) {
                                if(parts[i].contains("Bearer")){
                                    indiceBearer = i;
                                    break;
                                }
                            }
                            String authorization = parts[indiceBearer];
                            if(authorization.contains("%20")){
                                parts = authorization.split("%20");
                            }else if(authorization.contains(" ")){
                                parts = authorization.split(" ");
                            }
                            for (int i = 0; i < parts.length; i++) {
                                    if(parts[i].startsWith("ey")){//El token empieza 
                                        indiceToken=i;
                                        break;
                                    }
                            }
                            auth = "Bearer "+parts[indiceToken].replaceAll("\"", "");
                            System.out.println(auth);
                        }else{
                            setError(response);
                        }
                    }else{
                        setError(response);
                    }
                }else{
                    auth = request.getHeader("Authorization");  
                }
                try{
                    respuesta = postRequest.getRespueta(auth.replaceAll("\"", ""));
                }catch(Exception ex){
                    setError(response);
                }
                valid = new JSONObject(respuesta);
                if (valid.getBoolean("status")) {
                    List<Object> vistas=new ArrayList<>();
                    JSONObject menu=new JSONObject(valid.getString("menu"));//Obtiene el menu
                    System.out.println(menu);
                    JSONArray menus = menu.getJSONArray("menu");
                    System.out.println(menus.toString());
                    for (int i = 0; i < menus.length(); i++) {
                        JSONObject obj = new JSONObject(menus.get(i).toString());
                        JSONArray getVistas=new JSONArray(obj.get("vistas").toString());
                        List<Object> views=getVistas.toList();
                        HashSet hs = new HashSet();
                        hs.addAll(views);
                        vistas.addAll(hs);
                    }
              
                    vistas.add("main.jsp");//Agregando la vista principal
                    String ruta = request.getRequestURI();
                    int indice = GeneralUtils.obtenerIndex(ruta);
                    String rutaJsp = ruta.substring(indice, ruta.length());

                    if(url.contains(".jsp")){
                        boolean acceso = addVistas(vistas,rutaJsp);
                        if(!acceso){
                            setError(response);
                        }
                    }
//                    List<String> views = (List<String>) ;
                    chain.doFilter(request, response);
                } else {
//                    sendError(response);
                    /*Borrando credenciales*/
                    deleteCredenciales(request, response);
                    request.getRequestDispatcher("/vistas/index.jsp").forward(request, response);
                }
            }
//        } else {
//            sendError(response);
//        }
    }
    private void deleteCredenciales(HttpServletRequest request,HttpServletResponse response){
        Cookie cookieAuth=new Cookie("Authorization", "");
        Cookie cookieMenu=new Cookie("menu", "");
        cookieAuth.setMaxAge(0);
        cookieMenu.setMaxAge(0);
        response.addCookie(cookieAuth);
        response.addCookie(cookieMenu);
    }
    private boolean addVistas(List<Object> vistas,String rutaJsp){
        for(int i= 0;vistas.size()>i;i++){
            Object vista = vistas.get(i);
            /*Esta condicional solo aplica cuando sí se tiene páginas detalle propias del sistema (que no estan registrados en SEGURIDAD) mas informacion VistasExtras.java */
            switch(vista.toString()){//Agrega las vistas detalle
                case VistasExtras.MANTENIMIENTO_PERSONA:VistasExtras.getVistasExtrasMantenimientoPersona(vistas); break;
                case VistasExtras.OTROS:VistasExtras.getVistasExtrasMantenimientoOtros(vistas);break;//Ejemplo
                case VistasExtras.REPORTE_PERSONA:VistasExtras.getVistasExtrasMantenimientoOtros(vistas);break;
            }
            System.out.println("Vista : "+vista +" rutaJSP : "+rutaJsp);
            if(vista.toString().equalsIgnoreCase(rutaJsp)){
                return true;
            }
        }
        return false;
    }
    private void sendError (HttpServletResponse response) throws IOException{
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.sendError(401);
    }
    public void setError(HttpServletResponse response) throws IOException{
        Response.ResponseBuilder builder = null;
        sendError(response);
        builder = Response.status(Response.Status.UNAUTHORIZED).entity(response);
        throw new WebApplicationException(builder.build());
    }
    @Override
    public void destroy() {

    }

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}