package com.airlock.iam.oauth2.domain.model.resource;

import com.airlock.iam.base.api.domain.model.exception.ViolationException;
import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.base.misc.log.LogUtil;
import com.airlock.iam.common.api.domain.model.user.PersistentUser;
import com.airlock.iam.core.application.configuration.contextdata.DateContextDataItemNameConfig;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.oauth2.api.domain.model.OAuth2ClientId;
import com.airlock.iam.oauth2.api.domain.model.OAuth2Scope;
import com.airlock.iam.oauth2.api.domain.model.claims.conditions.ClaimCondition;
import com.airlock.iam.oauth2.application.configuration.resource.OAuth2LocalDateContextDataResourceProviderConfig;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import java.util.Set;

@LogicForConfig(OAuth2LocalDateContextDataResourceProviderConfig.class)
public final class OAuth2LocalDateContextDataResourceProvider implements OAuth2ResourceProvider {
   private static final ELogger LOG = ELoggerFactory.getLogger(OAuth2LocalDateContextDataResourceProvider.class);
   private final Provider<OAuth2ResourceIdentifier> identifier;
   private final Provider<DateContextDataItemNameConfig> config;
   private final Provider<DateTimeFormatter> dateFormat;
   private final Provider<Optional<ClaimCondition>> condition;

   @Inject
   public OAuth2LocalDateContextDataResourceProvider(
      Provider<OAuth2ResourceIdentifier> identifier,
      Provider<DateContextDataItemNameConfig> config,
      Provider<DateTimeFormatter> dateFormat,
      Provider<Optional<ClaimCondition>> condition
   ) {
      this.identifier = identifier;
      this.config = config;
      this.dateFormat = dateFormat;
      this.condition = condition;
   }

   @Override
   public Optional<OAuth2ResourceResult> getResourceResult(PersistentUser user, Set<OAuth2Scope> givenScopes, OAuth2ClientId clientId) {
      if (((Optional)this.condition.get()).isPresent() && !((ClaimCondition)((Optional)this.condition.get()).get()).isSatisfied(givenScopes)) {
         return Optional.empty();
      } else {
         Optional<Object> data = Optional.ofNullable(user.getContextData().get(((DateContextDataItemNameConfig)this.config.get()).getContextDataName()));
         if (data.isEmpty()) {
            LOG.info(
               String.format(
                  "Missing %s context data value for user %s: Failed to add value for resource %s.",
                  LogUtil.quote(((DateContextDataItemNameConfig)this.config.get()).getContextDataName()),
                  LogUtil.quote(user.getName()),
                  LogUtil.quote(((OAuth2ResourceIdentifier)this.identifier.get()).getId())
               )
            );
            return Optional.empty();
         } else if (!(data.get() instanceof LocalDate)) {
            throw new ViolationException(
               String.format(
                  "Context data %s is not of type LocalDate, but of type %s",
                  LogUtil.quote(((DateContextDataItemNameConfig)this.config.get()).getContextDataName()),
                  LogUtil.quote(data.get().getClass().getName())
               )
            );
         } else {
            return Optional.of(
               OAuth2ResourceResult.resourceResult()
                  .add((OAuth2ResourceIdentifier)this.identifier.get(), ((DateTimeFormatter)this.dateFormat.get()).format((LocalDate)data.get()))
            );
         }
      }
   }
}
