package com.airlock.iam.oauth2.infrastructure.factory;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.oauth2.api.domain.model.claims.UserClaimExtractor;
import com.airlock.iam.oauth2.application.configuration.token.AccessTokenClaimsSettings;
import com.airlock.iam.oauth2.domain.model.settings.JwtAccessTokenFormatSettings;
import com.airlock.iam.oauth2.domain.model.settings.OAuth2AccessTokenSettings;
import com.airlock.iam.oauth2.domain.model.token.OAuth2ClientAccessTokenExtensionProvider;
import com.airlock.iam.oauth2.domain.service.OAuth2AccessTokenClaimsService;
import com.airlock.iam.oauth2.domain.service.OAuth2GrantsSessionService;
import com.airlock.iam.oauth2.infrastructure.service.OAuth2AccessTokenClaimsServiceImpl;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

public final class AccessTokenClaimServiceFactory {
   public static OAuth2AccessTokenClaimsService getClaimsService(
      OAuth2AccessTokenSettings accessTokenSettings,
      List<UserClaimExtractor<?>> defaultUserClaimExtractors,
      OAuth2ClientAccessTokenExtensionProvider staticClientAccessTokenExtensionProvider
   ) {
      return accessTokenClaimsService(
         accessTokenSettings.settings(),
         new AccessTokenClaimsSettings(
            accessTokenSettings.userStore(),
            accessTokenSettings.usernameTransformer(),
            accessTokenSettings.roleTransformationProvider(),
            accessTokenSettings.persistClaims(),
            staticClientAccessTokenExtensionProvider
         ),
         accessTokenSettings.sessionService().orElseThrow(() -> new FailureException("OAuth 2.0 session repository not configured")),
         defaultUserClaimExtractors
      );
   }

   private static OAuth2AccessTokenClaimsService accessTokenClaimsService(
      Optional<JwtAccessTokenFormatSettings> settings,
      AccessTokenClaimsSettings accessTokenClaimsSettings,
      OAuth2GrantsSessionService sessionService,
      List<UserClaimExtractor<?>> defaultUserClaimExtractors
   ) {
      return OAuth2AccessTokenClaimsServiceImpl.builder()
         .userStore(accessTokenClaimsSettings.userStore())
         .defaultUserClaimExtractors(defaultUserClaimExtractors)
         .clientExtensionProvider(accessTokenClaimsSettings.clientExtensionProvider())
         .defaultDistributedClaims(settings.flatMap(JwtAccessTokenFormatSettings::distributedClaims).orElse(null))
         .includeSubClaim(settings.map(JwtAccessTokenFormatSettings::includeSubjectClaim).orElse(false))
         .issuer(settings.map(JwtAccessTokenFormatSettings::issuer).orElse(null))
         .defaultAudience(settings.map(JwtAccessTokenFormatSettings::audience).orElseGet(Collections::emptyList))
         .usernameTransformer(accessTokenClaimsSettings.usernameTransformer())
         .isUsePersistedClaims(accessTokenClaimsSettings.isUsePersistedClaims())
         .sessionService(sessionService)
         .build();
   }
}
