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

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.core.misc.cronto.CrontoHandler;
import com.airlock.iam.core.misc.impl.cronto.CrontoOnlineTransaction;
import com.airlock.iam.core.misc.impl.cronto.CrontoSignSwissOnlineTransaction;
import com.airlock.iam.core.misc.impl.cronto.PendingCrontoTransaction;
import com.airlock.iam.core.misc.impl.cronto.pushnotification.PushAppHandlerWithActivation;
import com.airlock.iam.core.misc.util.ServletUtils;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.login.app.misc.cronto.application.CrontoApplicationResponseFormatter;
import com.airlock.iam.login.app.misc.cronto.application.CrontoMobileApplicationFormatterFactory;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Optional;

public class CrontoSignSwissOnlineValidationServlet extends CrontoAppCommunicationServlet {
   private static final ELogger LOG = ELoggerFactory.getLogger(CrontoSignSwissOnlineValidationServlet.class);
   private static final int GET_TRANSACTION_ERROR = 602;

   @Override
   protected void handleCrontoRequest(
      HttpServletRequest request, HttpServletResponse response, ConfigurationContext context, Optional<CrontoHandler> crontoHandler
   ) throws IOException {
      CrontoApplicationResponseFormatter formatter = CrontoMobileApplicationFormatterFactory.forRequest(request);
      if (!ServletUtils.isPOST(request)) {
         LOG.info("Discarding online validation request because it is not a POST request.");
         formatter.formatErrorResponse(response, "Invalid request.");
      } else if (crontoHandler.isEmpty()) {
         LOG.info("Discarding online validation request because there is no Cronto self-service configuration available.");
         formatter.formatErrorResponse(response, "Invalid request.");
      } else if (!crontoHandler.get().isPushNotificationEnabled()) {
         LOG.info("Discarding online validation request because the push notification feature is disabled.");
         formatter.formatErrorResponse(response, "Invalid request.");
      } else if (crontoHandler.get().getPushAppHandler() instanceof PushAppHandlerWithActivation pushAppHandler) {
         CrontoOnlineTransaction crontoOnlineTransaction = pushAppHandler.createOnlineTransaction(request);
         if (crontoOnlineTransaction instanceof CrontoSignSwissOnlineTransaction onlineTransaction) {
            if (!onlineTransaction.areNecessaryParametersPresent()) {
               LOG.info("Discarding online validation request because required parameters are missing.");
               formatter.formatErrorResponse(response, "Invalid request.");
            } else {
               LOG.debug("Handling Cronto online validation request of type " + onlineTransaction.getRequestType().get());

               try {
                  switch ((CrontoSignSwissOnlineTransaction.RequestType)onlineTransaction.getRequestType().get()) {
                     case GET_TRANSACTION:
                        retrieveTransactionList(response, pushAppHandler, formatter, onlineTransaction);
                        break;
                     case VALIDATE_TRANSACTION:
                     case REJECT_TRANSACTION:
                        handleTransaction(onlineTransaction, crontoHandler.get(), response, formatter);
                        break;
                     default:
                        formatter.formatErrorResponse(response, "Invalid request.");
                  }
               } catch (RuntimeException e) {
                  LOG.warn(LogTypes.SERVLET_EXCEPTION_HANDLER, "Exception during Cronto online validation request: " + e.getMessage());
                  formatter.formatErrorResponse(response, "Invalid request.");
               }
            }
         } else {
            throw new FailureException("Online transaction is of wrong type: " + crontoOnlineTransaction.getClass());
         }
      } else {
         throw new FailureException("Cronto handler is of wrong type: " + crontoHandler.get().getPushAppHandler().getClass());
      }
   }

   private static void retrieveTransactionList(
      HttpServletResponse response,
      PushAppHandlerWithActivation pushAppHandler,
      CrontoApplicationResponseFormatter formatter,
      CrontoSignSwissOnlineTransaction crontoEngineOnlineTransaction
   ) throws IOException {
      Optional<PendingCrontoTransaction> pendingCrontoTransaction = pushAppHandler.retrieveTransactionDetails(crontoEngineOnlineTransaction);
      if (pendingCrontoTransaction.isEmpty()) {
         formatter.formatErrorResponse(response, 602, "No pending transactions could be found.");
      } else {
         formatter.formatTransactionListResponse(response, Arrays.asList(pendingCrontoTransaction.get()));
      }
   }

   private static void handleTransaction(
      CrontoOnlineTransaction crontoOnlineTransaction, CrontoHandler crontoHandler, HttpServletResponse response, CrontoApplicationResponseFormatter formatter
   ) throws IOException {
      crontoHandler.commitCrontoResponse(crontoOnlineTransaction);
      formatter.formatSuccessResponse(response);
   }
}
