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

import com.airlock.iam.base.api.domain.model.exception.ServiceConfigurationException;
import com.airlock.iam.base.api.domain.model.user.UserId;
import com.airlock.iam.oauth2.api.domain.model.AuthorizationServerId;
import com.airlock.iam.oauth2.api.domain.model.OAuth2ClientId;
import com.airlock.iam.oauth2.domain.model.consent.OAuth2Consent;
import com.airlock.iam.oauth2.domain.model.consent.OAuth2ConsentId;
import com.airlock.iam.oauth2.domain.model.consent.OAuth2ConsentRepository;
import com.airlock.iam.oauth2.domain.model.consent.OAuth2ConsentStatus;
import com.airlock.iam.oauth2.domain.service.OAuth2ConsentService;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public final class DefaultOAuth2ConsentService implements OAuth2ConsentService {
   private final Provider<Optional<OAuth2ConsentRepository>> repository;

   @Inject
   public DefaultOAuth2ConsentService(Provider<Optional<OAuth2ConsentRepository>> repository) {
      this.repository = repository;
   }

   @Override
   public Optional<OAuth2Consent> get(UserId userId, OAuth2ConsentId consentId) {
      return this.repository().get(consentId).filter(consent -> consent.getUserId().equals(userId));
   }

   @Override
   public Collection<OAuth2Consent> findByUser(UserId userId) {
      return this.repository().findByUser(userId);
   }

   @Override
   public void grantConsent(OAuth2ConsentId consentId, UserId userId) {
      this.repository().updateStatus(consentId, userId, OAuth2ConsentStatus.GRANTED);
   }

   @Override
   public void denyConsent(OAuth2ConsentId consentId, UserId userId) {
      this.repository().updateStatus(consentId, userId, OAuth2ConsentStatus.DENIED);
   }

   @Override
   public Collection<OAuth2Consent> findByUserAndAuthorizationServer(UserId userId, AuthorizationServerId authorizationServerId) {
      return this.repository().findByUserAndAuthorizationServer(userId, authorizationServerId);
   }

   @Override
   public void delete(OAuth2ConsentId consentId) {
      this.repository().delete(consentId);
   }

   @Override
   public Map<AuthorizationServerId, List<OAuth2ClientId>> findAuthorizationServersAndClientsForUser(UserId userId) {
      Map<AuthorizationServerId, List<OAuth2ClientId>> asInfo = new HashMap<>();

      for (OAuth2ConsentRepository.AuthorizationServerAndClient asClientPair : this.repository().findAuthorizationServersAndClientsForUser(userId)) {
         if (asInfo.containsKey(asClientPair.getAuthorizationServerId())) {
            asInfo.get(asClientPair.getAuthorizationServerId()).add(asClientPair.getClientId());
         } else {
            asInfo.put(asClientPair.getAuthorizationServerId(), new ArrayList<>(List.of(asClientPair.getClientId())));
         }
      }

      return asInfo;
   }

   private OAuth2ConsentRepository repository() {
      return ServiceConfigurationException.checkPresent((Optional<OAuth2ConsentRepository>)this.repository.get(), "OAuth 2.0 consent repository not configured");
   }
}
