package com.airlock.iam.servicecontainer.app.application.configuration.radius;

import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.license.PluginLicenseRestriction;
import com.airlock.iam.plugin.api.annotation.property.BooleanProperty;
import com.airlock.iam.plugin.api.annotation.property.RegexProperty;
import com.airlock.iam.plugin.api.annotation.property.RegexProperty.CaseSensitivitySelector;
import com.airlock.iam.servicecontainer.app.application.service.radius.wrapper.lib.IamRadiusServerAccessRequest;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.net.InetAddress;
import java.util.Optional;
import java.util.regex.Pattern;

@Plugin(
   description = "This target service is associated with a NAS identifier.<p>The target service is meant to be used if a NAS identifier, sent by a RADIUS client, matches the one in the configuration.</p>",
   displayName = "NAS-based Target Service"
)
@PluginLicenseRestriction(moduleAffiliation = "RadiusServer")
public final class NASBasedTargetServiceConfig extends TargetServiceConfig {
   private static final ELogger LOG = ELoggerFactory.getLogger(NASBasedTargetServiceConfig.class);
   @RegexProperty(
      displayName = "NAS Identifier Pattern",
      description = "The NAS-Identifier (if available) is matched against this pattern. If it matches, this target service is chosen.",
      optional = false,
      caseSensitivity = CaseSensitivitySelector.CONFIGURED_BY_PROPERTY,
      caseSensitivityProperty = "matchCaseSensitive",
      exampleValues = {"OWA", ".*-intra-.*"}
   )
   private Pattern nasIdentifierPattern;
   @BooleanProperty(
      description = "Disable to match case-insensitive when matching the NAS-Identifier against this target service's pattern.",
      optional = true,
      defaultValue = "true"
   )
   private boolean matchCaseSensitive;

   @Override
   public boolean matches(IamRadiusServerAccessRequest request, InetAddress sourceAddress) {
      Optional<String> extractedNAS = extractNASIdentifier(request);
      if (extractedNAS.isEmpty()) {
         LOG.debug("NAS identifier is not available!");
         return false;
      } else {
         return this.doesNASMatch(extractedNAS.get());
      }
   }

   private static Optional<String> extractNASIdentifier(IamRadiusServerAccessRequest request) {
      Object nasIdentifier = request.attributeValue(32);
      return nasIdentifier instanceof String ? Optional.of((String)nasIdentifier) : Optional.empty();
   }

   private boolean doesNASMatch(String extractedNAS) {
      if (this.nasIdentifierPattern.matcher(extractedNAS).matches()) {
         LOG.info("Successfully matched NAS: \"" + extractedNAS + "\"");
         return true;
      } else {
         LOG.info("NAS identifier: \"" + extractedNAS + "\" could not be matched.");
         return false;
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   public static NASBasedTargetServiceConfig.NASBasedTargetServiceConfigBuilder builder() {
      return new NASBasedTargetServiceConfig.NASBasedTargetServiceConfigBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public NASBasedTargetServiceConfig(Pattern nasIdentifierPattern, boolean matchCaseSensitive) {
      this.nasIdentifierPattern = nasIdentifierPattern;
      this.matchCaseSensitive = matchCaseSensitive;
   }

   @SuppressFBWarnings(justification = "generated code")
   public NASBasedTargetServiceConfig() {
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class NASBasedTargetServiceConfigBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private Pattern nasIdentifierPattern;
      @SuppressFBWarnings(justification = "generated code")
      private boolean matchCaseSensitive;

      @SuppressFBWarnings(justification = "generated code")
      NASBasedTargetServiceConfigBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public NASBasedTargetServiceConfig.NASBasedTargetServiceConfigBuilder nasIdentifierPattern(Pattern nasIdentifierPattern) {
         this.nasIdentifierPattern = nasIdentifierPattern;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public NASBasedTargetServiceConfig.NASBasedTargetServiceConfigBuilder matchCaseSensitive(boolean matchCaseSensitive) {
         this.matchCaseSensitive = matchCaseSensitive;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public NASBasedTargetServiceConfig build() {
         return new NASBasedTargetServiceConfig(this.nasIdentifierPattern, this.matchCaseSensitive);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "NASBasedTargetServiceConfig.NASBasedTargetServiceConfigBuilder(nasIdentifierPattern="
            + this.nasIdentifierPattern
            + ", matchCaseSensitive="
            + this.matchCaseSensitive
            + ")";
      }
   }
}
