package com.airlock.iam.admin.domain.model.realm;

import com.airlock.iam.admin.api.domain.model.administrator.CurrentAdministrator;
import com.airlock.iam.admin.application.configuration.realm.RealmUsernameValidatorConfig;
import com.airlock.iam.admin.domain.model.contextdata.AdminRealmContextDataName;
import com.airlock.iam.base.api.domain.model.plugin.LogicForConfig;
import com.airlock.iam.base.api.domain.model.validation.GenericError;
import com.airlock.iam.base.api.domain.model.validation.ValidationResult;
import com.airlock.iam.base.api.domain.model.validation.Validator;
import com.airlock.iam.base.api.domain.model.validation.ValidatorError;
import com.airlock.iam.base.api.domain.model.validation.info.RegexValidationInfo;
import com.airlock.iam.base.api.domain.model.validation.info.ValidationInfo;
import jakarta.inject.Inject;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;

@LogicForConfig(RealmUsernameValidatorConfig.class)
public final class RealmUsernameValidator implements Validator<String> {
   private final CurrentAdministrator admin;
   private final RealmUsernameValidatorConfig config;
   private final Optional<AdminRealmContextDataName> adminRealmContextDataName;

   @Inject
   public RealmUsernameValidator(CurrentAdministrator admin, RealmUsernameValidatorConfig config, Optional<AdminRealmContextDataName> adminRealmContextDataName) {
      this.admin = admin;
      this.config = config;
      this.adminRealmContextDataName = adminRealmContextDataName;
   }

   public ValidationResult validate(String username) {
      return this.getResolvedUsernamePattern().map(pattern -> this.usernameMatchesRealmPattern(pattern, username)).orElse(ValidationResult.valid());
   }

   public List<ValidationInfo> getInfo() {
      return this.getResolvedUsernamePattern()
         .map(Pattern::compile)
         .<Object>map(RegexValidationInfo::create)
         .map(ValidationInfo.class::cast)
         .map(List::of)
         .orElse(List.of());
   }

   private Optional<String> getResolvedUsernamePattern() {
      return this.adminRealmContextDataName
         .<String>flatMap(name -> name.getValidatedValue(this.admin))
         .map(realm -> this.config.getUsernamePattern().replace("@realm@", realm));
   }

   private ValidationResult usernameMatchesRealmPattern(String pattern, String username) {
      return username.matches(pattern)
         ? ValidationResult.valid()
         : ValidationResult.invalid(ValidatorError.validatorErrorBuilder("username", GenericError.WRONG_FORMAT));
   }
}
