package com.airlock.iam.login.infrastructure.session;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.api.domain.model.mapification.MapifiedValues;
import com.airlock.iam.base.domain.model.mapification.MapifiedValuesBuilder;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.flow.api.domain.model.flow.FlowId;
import com.airlock.iam.flow.application.configuration.flow.FlowConfigHash;
import com.airlock.iam.flow.domain.model.session.GenericMultiFlowSession;
import com.airlock.iam.flow.domain.model.session.MultiFlowSession;
import com.airlock.iam.flow.shared.domain.model.session.MultiFlowSessionMapifier;
import com.airlock.iam.flow.types.api.domain.model.session.KnownMultiFlowType;
import com.airlock.iam.flow.types.api.domain.model.session.MultiFlowType;
import jakarta.inject.Inject;
import java.util.List;

public final class MultiFlowSessionMapifierImpl implements MultiFlowSessionMapifier {
   private static final String CONFIG_HASHES_KEY = "configHashes";
   private static final String FLOW_ID_KEY = "flowId";
   private static final String MULTI_FLOW_TYPE_KEY = "type";
   private static final String NUM_COMPLETED_KEY = "numCompleted";

   @Override
   public MapifiedValues mapifyMultiFlowSession(MultiFlowSession session) {
      if (session instanceof GenericMultiFlowSession multiFlowSession) {
         return MapifiedValuesBuilder.mapifiedValues()
            .put("configHashes", multiFlowSession.getConfigHashes().stream().map(MultiFlowSessionMapifierImpl::serializeFlowConfigHash).toList())
            .put("numCompleted", multiFlowSession.getNumFlowsCompleted())
            .put("type", serializeMultiFlowType(session.getType()))
            .put("flowId", serializeFlowId(multiFlowSession))
            .build();
      } else {
         throw new FailureException("Unknown MultiFlowSession implementation: " + LogUtil.quote(session.getClass().getName()));
      }
   }

   @Override
   public MultiFlowSession demapifyMultiFlowSession(MapifiedValues values) {
      return new GenericMultiFlowSession(
         values.simpleValue("configHashes", MultiFlowSessionMapifierImpl::deserializeFlowConfigHashes),
         values.simpleValue("type", MultiFlowSessionMapifierImpl::deserializeMultiFlowType),
         values.simpleValue("flowId", MultiFlowSessionMapifierImpl::deserializeFlowId),
         values.<Integer>get("numCompleted")
      );
   }

   private static String serializeMultiFlowType(MultiFlowType multiFlowType) {
      return multiFlowType.name();
   }

   private static MultiFlowType deserializeMultiFlowType(Object value) {
      return KnownMultiFlowType.valueOf((String)value);
   }

   private static String serializeFlowId(GenericMultiFlowSession session) {
      return session.getCurrentFlowId().toString();
   }

   private static FlowId deserializeFlowId(Object value) {
      return new FlowId((String)value);
   }

   private static int serializeFlowConfigHash(FlowConfigHash flowConfigHash) {
      return flowConfigHash.getFlowConfigHashCode();
   }

   private static FlowConfigHash deserializeFlowConfigHash(Object flowConfigHash) {
      return FlowConfigHash.of((Integer)flowConfigHash);
   }

   private static List<FlowConfigHash> deserializeFlowConfigHashes(Object configHashes) {
      return ((List)configHashes).stream().map(MultiFlowSessionMapifierImpl::deserializeFlowConfigHash).toList();
   }
}
