package com.airlock.iam.saml2.infrastructure.state;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.domain.model.mapification.MapifiedValuesBuilder;
import com.airlock.iam.base.misc.json.JsonCoding;
import com.sun.identity.saml2.common.NameIDInfo;
import com.sun.identity.saml2.common.SAML2Exception;
import com.sun.identity.saml2.profile.SPFedSession;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

final class SPFedSessionListSerializer implements Serializer<List<SPFedSession>> {
   private static final String SESSIONS_KEY = "sessions";
   private static final String IDP_SESSION_INDEX_KEY = "idpSessionIndex";
   private static final String SP_TOKEN_ID_KEY = "spTokenID";
   private static final String INFO_KEY = "info";
   private static final String META_ALIAS_KEY = "metaAlias";

   public String mapToStore(List<SPFedSession> sessions) {
      return JsonCoding.toJson(Map.of("sessions", sessions.stream().map(SPFedSessionListSerializer::serializeSession).toList()));
   }

   private static Map<String, String> serializeSession(SPFedSession session) {
      return MapifiedValuesBuilder.mapifiedValues()
         .putIfPresent("idpSessionIndex", Optional.ofNullable(session.idpSessionIndex))
         .putIfPresent("spTokenID", Optional.ofNullable(session.spTokenID))
         .putIfPresent("info", Optional.ofNullable(session.info).map(NameIDInfo::toValueString))
         .putIfPresent("metaAlias", Optional.ofNullable(session.metaAlias))
         .build()
         .asStringStringMap();
   }

   public List<SPFedSession> mapFromStore(String serialized) {
      return ((List)JsonCoding.fromJson(serialized).get("sessions"))
         .stream()
         .map(SPFedSessionListSerializer::deserializeSession)
         .collect(Collectors.toCollection(ArrayList::new));
   }

   private static SPFedSession deserializeSession(Map<String, String> values) {
      try {
         return new SPFedSession(
            values.get("idpSessionIndex"),
            values.get("spTokenID"),
            values.containsKey("info") ? NameIDInfo.parse(values.get("info")) : null,
            values.get("metaAlias")
         );
      } catch (SAML2Exception e) {
         throw new FailureException(e);
      }
   }
}
