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

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.common.api.domain.model.user.PersistentUser;
import com.airlock.iam.core.misc.util.ticket.KeyMultiValue;
import com.airlock.iam.core.misc.util.ticket.SecureTicketEncoder;
import com.airlock.iam.core.misc.util.ticket.Ticket;
import com.airlock.iam.core.misc.util.ticket.TicketEncodingException;
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.OAuth2SsoTicketResourceProviderConfig;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.TemporalAmount;
import java.util.List;
import java.util.Optional;
import java.util.Set;

@LogicForConfig(OAuth2SsoTicketResourceProviderConfig.class)
public final class OAuth2SsoTicketResourceProvider implements OAuth2ResourceProvider {
   private final Provider<OAuth2ResourceIdentifier> identifier;
   private final Provider<Duration> ticketLifetime;
   private final Provider<SecureTicketEncoder> encoder;
   private final Provider<List<String>> staticRoles;
   private final Provider<Optional<ClaimCondition>> condition;

   @Inject
   public OAuth2SsoTicketResourceProvider(
      Provider<OAuth2ResourceIdentifier> identifier,
      Provider<Duration> ticketLifetime,
      Provider<SecureTicketEncoder> encoder,
      Provider<List<String>> staticRoles,
      Provider<Optional<ClaimCondition>> condition
   ) {
      this.identifier = identifier;
      this.ticketLifetime = ticketLifetime;
      this.encoder = encoder;
      this.staticRoles = staticRoles;
      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();
      }

      Ticket ssoTicket = new Ticket(Instant.now().plus((TemporalAmount)this.ticketLifetime.get()));
      ssoTicket.generateUniqueId();
      ssoTicket.addKeyMultiValue(new KeyMultiValue("username", user.getName()));
      ssoTicket.addKeyMultiValue(new KeyMultiValue("roles", (List<String>)this.staticRoles.get()));

      try {
         String encoded = ((SecureTicketEncoder)this.encoder.get()).encode(ssoTicket, StandardCharsets.UTF_8.name());
         return Optional.of(OAuth2ResourceResult.resourceResult().add((OAuth2ResourceIdentifier)this.identifier.get(), encoded));
      } catch (TicketEncodingException e) {
         throw new FailureException("Error encoding ticket: " + e.getMessage(), e);
      }
   }
}
