package com.airlock.iam.authentication.domain.model.kerberos;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.api.domain.model.mapification.Mapifiable;
import com.airlock.iam.base.api.domain.model.mapification.MapifiedValues;
import com.airlock.iam.base.domain.model.mapification.MapifiedValuesBuilder;
import com.airlock.iam.common.api.application.dependency.injection.LegacyPluginInjectorFactory;
import com.airlock.iam.elog.api.EDefaultLogType;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.flow.api.domain.model.step.StepSession;
import jakarta.servlet.http.HttpSession;
import java.util.Optional;
import java.util.function.Supplier;
import org.ietf.jgss.GSSContext;

public class KerberosAuthStepSession implements StepSession, Mapifiable {
   private static final ELogger LOG = ELoggerFactory.getLogger(KerberosAuthStepSession.class);
   private static final String GSS_CONTEXT_ATTR = "KerberosGssContext";
   private static final String HAS_GSS_CONTEXT_KEY = "hasGssContext";
   private Optional<Supplier<GSSContext>> gssContextSupplier = Optional.empty();

   public void setGssContext(Optional<GSSContext> gssContext) {
      this.gssContextSupplier = gssContext.map(context -> () -> context);
   }

   public Optional<GSSContext> getGssContext() {
      return this.gssContextSupplier.map(Supplier::get);
   }

   @Override
   public MapifiedValues mapify() {
      if (this.gssContextSupplier.isPresent()) {
         try {
            httpSession().setAttribute("KerberosGssContext", this.gssContextSupplier.get().get());
         } catch (FailureException e) {
            LOG.warn(EDefaultLogType.GENERIC_LOG_TYPE, "Ignoring exception: " + e.getMessage());
         }
      }

      return MapifiedValuesBuilder.mapifiedValues().put("hasGssContext", this.gssContextSupplier.isPresent()).build();
   }

   public static KerberosAuthStepSession demapify(MapifiedValues values) {
      KerberosAuthStepSession result = new KerberosAuthStepSession();
      if (values.getBoolean("hasGssContext")) {
         GSSContext gss = (GSSContext)httpSession().getAttribute("KerberosGssContext");
         if (gss != null) {
            result.gssContextSupplier = Optional.of(() -> gss);
         } else {
            result.gssContextSupplier = Optional.of(
               () -> {
                  throw new FailureException(
                     "Expected to find GssContext but was empty. Maybe because stateless IAM only supports 'one-shot' use-cases of SPNEGO/Kerberos."
                  );
               }
            );
         }
      }

      return result;
   }

   private static HttpSession httpSession() {
      return LegacyPluginInjectorFactory.getInjector().getInstance(HttpSession.class);
   }
}
