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

import com.airlock.iam.common.api.domain.model.user.CurrentLocale;
import com.airlock.iam.common.domain.model.locale.LocalePreferences;
import com.airlock.iam.oauth2.domain.model.OAuth2Language;
import com.airlock.iam.oauth2.domain.model.codegrant.OpenIdConnectAuthenticationRequest;
import jakarta.inject.Inject;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.Locale.LanguageRange;
import java.util.stream.Collectors;

public final class OpenIdConnectUiLocaleFlowHandler {
   private final LocalePreferences localePreferences;
   private final CurrentLocale currentLocale;

   @Inject
   public OpenIdConnectUiLocaleFlowHandler(LocalePreferences localePreferences, CurrentLocale currentLocale) {
      this.localePreferences = localePreferences;
      this.currentLocale = currentLocale;
   }

   public Optional<Locale> determineLocaleAndUpdateCurrentLocale(OpenIdConnectAuthenticationRequest authenticationRequest) {
      List<String> requestedUiLocales = authenticationRequest.getUiLocales().stream().map(OAuth2Language::asLanguageTagString).collect(Collectors.toList());
      if (!requestedUiLocales.isEmpty()) {
         Locale localeFromRequest = this.localePreferences.forLanguagesInOrder(requestedUiLocales);
         if (this.isDefaultEqualsRequestedLocale(localeFromRequest)
            && !this.containsLocaleInRequestedLocales(this.localePreferences.getDefaultLocale(), requestedUiLocales)) {
            return Optional.of(this.currentLocale.get());
         }

         this.currentLocale.update(localeFromRequest);
         return Optional.of(localeFromRequest);
      } else {
         return Optional.empty();
      }
   }

   private boolean isDefaultEqualsRequestedLocale(Locale localeFromRequest) {
      return localeFromRequest.equals(this.localePreferences.getDefaultLocale());
   }

   private boolean containsLocaleInRequestedLocales(Locale locale, List<String> requestedUiLocales) {
      List<LanguageRange> ranges = requestedUiLocales.stream().map(LanguageRange::new).collect(Collectors.toList());
      return Locale.lookup(ranges, List.of(locale)) != null;
   }
}
