package com.airlock.iam.saml2.domain.model.assertion.attribute;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.flow.shared.domain.model.session.SuccessfulAuthenticationTimestamp;
import com.airlock.iam.saml2.application.configuration.assertion.attribute.AuthenticationInstantAttributeConfig;
import com.airlock.iam.saml2.domain.model.assertion.FlowSaml2Attribute;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.time.Instant;
import java.util.Date;
import java.util.Optional;
import org.apache.commons.lang3.time.FastDateFormat;

@LogicForConfig(AuthenticationInstantAttributeConfig.class)
public class Saml2AuthenticationInstantAttributeImpl implements Saml2AttributeProvider {
   private final AuthenticationInstantAttributeConfig config;
   private final Provider<Optional<SuccessfulAuthenticationTimestamp>> authenticationTimestamp;

   @Inject
   public Saml2AuthenticationInstantAttributeImpl(
      AuthenticationInstantAttributeConfig config, Provider<Optional<SuccessfulAuthenticationTimestamp>> authenticationTimestamp
   ) {
      this.config = config;
      this.authenticationTimestamp = authenticationTimestamp;
   }

   @Override
   public Optional<FlowSaml2Attribute> getAttribute() {
      return Optional.of(
         new FlowSaml2Attribute(
            this.config.getSamlAttributeName(), this.formatAuthenticationInstant(this.getAuthenticationInstant()), this.config.getNameFormat()
         )
      );
   }

   private Instant getAuthenticationInstant() {
      return ((SuccessfulAuthenticationTimestamp)((Optional)this.authenticationTimestamp.get())
            .orElseThrow(() -> new FailureException("No SuccessfulAuthenticationTimestamp available")))
         .getAuthenticationTime();
   }

   private String formatAuthenticationInstant(Instant instant) {
      Optional<FastDateFormat> dateAndTimeFormat = this.config.getDateAndTimeFormat();
      return dateAndTimeFormat.isPresent() ? dateAndTimeFormat.get().format(Date.from(instant)) : Long.toString(instant.toEpochMilli());
   }
}
