package com.airlock.iam.oauth2.application.service;

import com.airlock.iam.base.misc.log.LogUtil;
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.OpenIdConnectSessionManagementSettings;
import com.airlock.iam.oauth2.domain.model.WebOrigin;
import com.airlock.iam.oauth2.domain.model.client.OAuth2Client;
import com.airlock.iam.oauth2.domain.model.client.OAuth2ClientLoader;
import com.airlock.iam.oauth2.domain.model.validation.CheckOriginResult;
import jakarta.inject.Inject;
import java.net.URI;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Stream;

public final class OpenIdConnectSessionManagementService {
   private static final ELogger LOG = ELoggerFactory.getLogger(OpenIdConnectSessionManagementService.class);
   private final OAuth2ClientLoader clientLoader;
   private final boolean debug;

   @Inject
   public OpenIdConnectSessionManagementService(OAuth2ClientLoader clientLoader, OpenIdConnectSessionManagementSettings sessionManagementSettings) {
      this.clientLoader = clientLoader;
      this.debug = sessionManagementSettings.isDebug();
   }

   public CheckOriginResult isOriginAllowed(OAuth2ClientId clientId, String origin) {
      Optional<OAuth2Client> client = this.clientLoader.tryLoadClient(clientId);
      if (client.isEmpty()) {
         if (this.debug) {
            LOG.debug(String.format("Client with ID %s not found.", LogUtil.quote(clientId)));
         }

         return new CheckOriginResult(false);
      } else {
         boolean isValid = client.<Boolean>map(c -> this.redirectUriOrigins(c).anyMatch(this.matchingOrigin(origin))).orElse(false);
         if (!isValid && this.debug) {
            LOG.debug(
               String.format(
                  "Origin check not successful: Requested origin %s does not match any of the redirect URIs of client %s: %s",
                  LogUtil.quote(origin),
                  LogUtil.quote(clientId),
                  client.get().redirectUris()
               )
            );
         }

         return new CheckOriginResult(isValid);
      }
   }

   private Stream<WebOrigin> redirectUriOrigins(OAuth2Client c) {
      return c.redirectUris().stream().map(uri -> WebOrigin.webOrigin(URI.create(uri)));
   }

   private Predicate<WebOrigin> matchingOrigin(String origin) {
      return webOrigin -> webOrigin.getOrigin().equals(origin);
   }
}
