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

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.domain.service.uri.UrlUtils;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.common.api.domain.model.role.Role;
import com.airlock.iam.common.domain.service.role.RolesSerializer;
import com.airlock.iam.common.domain.service.sso.ContextDataEntry;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;

final class SsoFlowSessionAttributesSeralizer {
   private static final ELogger LOG = ELoggerFactory.getLogger(SsoFlowSessionAttributesSeralizer.class);
   static final String ROLES_KEY = "roles";
   static final String CONTEXT_DATA_KEY = "contextData";
   private static final String DATA_SEPARATOR = "&";
   private static final String KEY_VALUE_SEPARATOR = "=";
   private static final String LIST_SEPARATOR = ",";
   private static final String LIST_START = "[";
   private static final String LIST_END = "]";

   public static Set<Role> deserializeRoles(Map<String, String> values) {
      return RolesSerializer.deserializeRoles(values.get("roles"));
   }

   public static Set<ContextDataEntry> deserializeContextData(Map<String, String> values) {
      String rawContextData = values.get("contextData");
      return StringUtils.isBlank(rawContextData)
         ? Set.of()
         : Pattern.compile("&")
            .splitAsStream(rawContextData)
            .map(UrlUtils::urlDecode)
            .map(SsoFlowSessionAttributesSeralizer::decodeContextDataEntry)
            .collect(Collectors.toSet());
   }

   private static ContextDataEntry decodeContextDataEntry(String contextDataString) {
      String[] keyValue = contextDataString.split("=");
      if (keyValue.length != 2) {
         LOG.debug("Cannot decode " + LogUtil.logSafeString(contextDataString));
         throw new FailureException("Cannot decode context data");
      }

      String key = UrlUtils.urlDecode(keyValue[0]);
      String rawValue = keyValue[1];
      if (rawValue.startsWith("[")) {
         if (!rawValue.endsWith("]")) {
            LOG.debug("Illegal list value: " + LogUtil.logSafeString(rawValue) + " for key: '" + key + "'");
            throw new FailureException("Illegal list value for key: '" + key + "'");
         } else {
            List<String> values = Pattern.compile(",").splitAsStream(rawValue.substring(1, rawValue.length() - 1)).map(UrlUtils::urlDecode).toList();
            return ContextDataEntry.contextData(key, values);
         }
      } else {
         return ContextDataEntry.contextData(key, UrlUtils.urlDecode(rawValue));
      }
   }

   private SsoFlowSessionAttributesSeralizer() {
   }
}
