package com.airlock.iam.saml2.domain.model.idp;

import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
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.session.FlowAttributeRepository;
import com.airlock.iam.flow.shared.domain.model.uitenantid.UiTenantId;
import com.airlock.iam.flow.shared.domain.model.uitenantid.UiTenantIdRule;
import com.airlock.iam.saml2.application.configuration.idp.Saml2SpEntityIdPatternUiTenantIdRuleConfig;
import com.airlock.iam.saml2.domain.model.sp.Saml2SpEntityId;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.Optional;
import java.util.regex.Matcher;

@LogicForConfig(Saml2SpEntityIdPatternUiTenantIdRuleConfig.class)
public final class Saml2SpEntityIdPatternUiTenantIdRule implements UiTenantIdRule {
   private static final ELogger LOG = ELoggerFactory.getLogger(Saml2SpEntityIdPatternUiTenantIdRule.class);
   private final Provider<FlowAttributeRepository> attributeRepository;
   private final Provider<Saml2SpEntityIdPatternUiTenantIdRuleSettings> settings;

   @Inject
   public Saml2SpEntityIdPatternUiTenantIdRule(
      Provider<FlowAttributeRepository> attributeRepository, Provider<Saml2SpEntityIdPatternUiTenantIdRuleSettings> settings
   ) {
      this.attributeRepository = attributeRepository;
      this.settings = settings;
   }

   @Override
   public Optional<UiTenantId> getUiTenantId() {
      return ((FlowAttributeRepository)this.attributeRepository.get())
         .tryGetAttribute(Saml2SpInitiatedRequestAttribute.class)
         .map(Saml2SpInitiatedRequestAttribute::getSpEntityId)
         .flatMap(this::uiTenantIdValue);
   }

   private Optional<UiTenantId> uiTenantIdValue(Saml2SpEntityId spEntityId) {
      Matcher matcher = ((Saml2SpEntityIdPatternUiTenantIdRuleSettings)this.settings.get()).spEntityIdPattern().matcher(spEntityId.value());
      if (!matcher.matches()) {
         return Optional.empty();
      }

      try {
         return Optional.of(matcher.replaceFirst(((Saml2SpEntityIdPatternUiTenantIdRuleSettings)this.settings.get()).uiTenantIdValue())).map(UiTenantId::new);
      } catch (IndexOutOfBoundsException e) {
         LOG.warn(
            EDefaultLogType.GENERIC_LOG_TYPE,
            "The configured UI tenant ID value contains a back-reference that is not consistent with the configured SP entity ID pattern."
         );
         return Optional.empty();
      }
   }
}
