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

import com.airlock.iam.common.infrastructure.interceptor.InterceptorManager;
import com.airlock.iam.oauth2.api.domain.model.AuthorizationServerId;
import com.airlock.iam.oauth2.api.domain.model.OAuth2ClientId;
import com.airlock.iam.techclient.api.domain.model.MutableTechnicalClient;
import com.airlock.iam.techclient.api.domain.model.oauth2.MutableOAuth2TechnicalClientMetadata;
import com.airlock.iam.techclient.api.domain.service.client.TechnicalClientChangeInterceptor;
import com.airlock.iam.techclient.api.domain.service.client.oauth2.OAuth2MetadataChangeInterceptor;
import com.airlock.iam.techclient.auth.domain.model.oauth2.LoginOAuth2TechClientImpl;
import com.airlock.iam.techclient.auth.domain.model.oauth2.MutableOAuth2TechClient;
import com.airlock.iam.techclient.auth.domain.model.oauth2.OAuth2TechClient;
import com.airlock.iam.techclient.auth.domain.model.oauth2.OAuth2TechClientMetadataImpl;
import com.airlock.iam.techclient.auth.domain.service.repository.oauth2.OAuth2TechClientRepository;
import jakarta.inject.Inject;
import java.util.Collection;
import java.util.Optional;
import java.util.function.BiConsumer;

public final class OAuth2TechClientService {
   private final OAuth2TechClientRepository repository;
   private final InterceptorManager interceptorManager;

   @Inject
   public OAuth2TechClientService(OAuth2TechClientRepository repository, InterceptorManager interceptorManager) {
      this.repository = repository;
      this.interceptorManager = interceptorManager;
   }

   public OAuth2TechClient insert(OAuth2TechClient client) {
      OAuth2TechClient interceptedClient = this.runChangeInterceptors(
         client,
         (data, interceptor) -> interceptor.beforeTechnicalClientInsert(data),
         (data, interceptor) -> interceptor.beforeOAuth2MetadataInsert(client.getId(), data)
      );
      OAuth2TechClient readbackClient = this.repository.insert(interceptedClient);
      this.interceptorManager
         .runOperation(
            OAuth2MetadataChangeInterceptor.class,
            readbackClient.getMetadata(),
            (data, interceptor) -> interceptor.afterOAuth2MetadataInsert(readbackClient.getId(), data)
         );
      this.interceptorManager
         .runOperation(TechnicalClientChangeInterceptor.class, readbackClient, (data, interceptor) -> interceptor.afterTechnicalClientInsert(data));
      return readbackClient;
   }

   public Optional<OAuth2TechClient> findClient(AuthorizationServerId authorizationServerId, OAuth2ClientId clientId) {
      return this.repository.findBy(authorizationServerId, clientId);
   }

   public Collection<OAuth2TechClient> findAllClients() {
      return this.repository.findAll();
   }

   private OAuth2TechClient runChangeInterceptors(
      OAuth2TechClient client,
      BiConsumer<MutableTechnicalClient, TechnicalClientChangeInterceptor> techClientConsumer,
      BiConsumer<MutableOAuth2TechnicalClientMetadata, OAuth2MetadataChangeInterceptor> oauth2MetadataConsumer
   ) {
      MutableOAuth2TechClient mutableClient = LoginOAuth2TechClientImpl.asMutable(client);
      this.interceptorManager.runOperation(TechnicalClientChangeInterceptor.class, mutableClient, techClientConsumer);
      this.runOAuth2MetadataChangeInterceptor(mutableClient, oauth2MetadataConsumer);
      return client;
   }

   private void runOAuth2MetadataChangeInterceptor(
      MutableOAuth2TechClient client, BiConsumer<MutableOAuth2TechnicalClientMetadata, OAuth2MetadataChangeInterceptor> consumer
   ) {
      MutableOAuth2TechnicalClientMetadata metadata = OAuth2TechClientMetadataImpl.asMutable(client.getMetadata());
      this.interceptorManager.runOperation(OAuth2MetadataChangeInterceptor.class, metadata, consumer);
      client.setMetadata(metadata);
   }
}
