package com.airlock.iam.login.app.misc;

import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.login.app.infrastructure.filter.LoginappServletInjectorFactory;
import com.airlock.iam.login.app.infrastructure.web.LoginappSpaServletUtils;
import com.airlock.iam.login.app.misc.config.Configuration;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.system.version.CurrentVersion;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.util.Enumeration;
import org.apache.commons.lang3.StringUtils;

public abstract class ExceptionWrapperServlet extends HttpServlet {
   private static final long serialVersionUID = -374150158104828137L;
   private static final ELogger LOG = ELoggerFactory.getLogger(ExceptionWrapperServlet.class);
   private static final String DEBUG_DUMMY_NAME = "comx.airlock.iam.login.app.misc.httpdebug";
   private static final ELogger DEBUGLOG = ELoggerFactory.getLogger("comx.airlock.iam.login.app.misc.httpdebug");
   private static final String DEBUG_START_DELIMITER = "-------- START DEBUG INCOMING HTTP DATA --------";
   private static final String DEBUG_END_DELIMITER = "-------- END DEBUG INCOMING HTTP DATA --------";
   private LoginappServletInjectorFactory injectorFactory;

   protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {
      this.doGetOrPost(request, response);
   }

   protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
      this.doGetOrPost(request, response);
   }

   private void doGetOrPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
      long startTimeStamp = System.currentTimeMillis();
      Configuration.getInstance().checkConfigurationLoaded();
      this.logRequestStart(request);

      try {
         this.handleRequestInternal(request, response);
      } finally {
         long endTimeStamp = System.currentTimeMillis();
         if (LOG.isDebugEnabled()) {
            LOG.debug(
               "End of handling "
                  + request.getMethod()
                  + " request \""
                  + request.getRequestURL()
                  + "\" (took "
                  + (endTimeStamp - startTimeStamp)
                  + " ms including backend calls)"
            );
         }
      }
   }

   public void init() throws ServletException {
      this.injectorFactory = new LoginappServletInjectorFactory(this.getServletContext());
   }

   protected void logRequestStart(HttpServletRequest request) {
      HttpSession httpSession = request.getSession();
      if (httpSession.isNew()) {
         LOG.info(
            com.airlock.iam.elog.api.LogTypes.SERVER_INFO_SYS,
            "Created new HTTP session for request: JSESSIONID is "
               + LogUtil.quote(httpSession.getId())
               + " - User-Agent is "
               + LogUtil.logSafeQuote(request.getHeader("User-Agent"))
               + " - Airlock IAM version is "
               + LogUtil.quote(CurrentVersion.getDisplayString())
         );
      }

      if (LOG.isDebugEnabled()) {
         LOG.debug("Start of handling " + request.getMethod() + " request \"" + request.getRequestURL() + "\"");
      }
   }

   private void handleRequestInternal(HttpServletRequest request, HttpServletResponse response) {
      try {
         this.debuglogIncomingData(request);
         this.handleRequest(request, response, this.configurationContext());
      } catch (Throwable e) {
         LOG.warn(LogTypes.SERVLET_EXCEPTION_HANDLER, "Exception during servlet request", e);
         LoginappSpaServletUtils.redirectToSpa(request, response, "/error");
      }
   }

   private ConfigurationContext configurationContext() {
      return this.injectorFactory.getConfigurationContext();
   }

   protected abstract void handleRequest(HttpServletRequest var1, HttpServletResponse var2, ConfigurationContext var3) throws Exception;

   private void debuglogIncomingData(HttpServletRequest request) {
      if (DEBUGLOG.isDebugEnabled()) {
         DEBUGLOG.debug("-------- START DEBUG INCOMING HTTP DATA --------");
         DEBUGLOG.debug("URL= " + request.getMethod() + " " + request.getRequestURL());
         Enumeration<String> params = request.getParameterNames();

         while (params.hasMoreElements()) {
            String paramName = params.nextElement();
            DEBUGLOG.debug("Parameter[" + paramName + "]=" + StringUtils.join(request.getParameterValues(paramName), ","));
         }

         Enumeration<String> enm = request.getHeaderNames();

         while (enm.hasMoreElements()) {
            String headername = enm.nextElement();
            DEBUGLOG.debug("Header[" + headername + "]=" + request.getHeader(headername));
         }

         Cookie[] cookies = request.getCookies();
         if (cookies != null) {
            for (int i = 0; i < cookies.length; i++) {
               Cookie curCookie = cookies[i];
               DEBUGLOG.debug(
                  "Cookie["
                     + i
                     + "]: name="
                     + curCookie.getName()
                     + ", value="
                     + curCookie.getValue()
                     + ", domain="
                     + curCookie.getDomain()
                     + ", path="
                     + curCookie.getPath()
                     + ", maxage="
                     + curCookie.getMaxAge()
                     + ", secure="
                     + curCookie.getSecure()
               );
            }
         }

         DEBUGLOG.debug("-------- END DEBUG INCOMING HTTP DATA --------");
      }
   }
}
