package com.airlock.iam.admin.application.configuration.logviewer;

import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.lifecycle.AfterConfigActivation;
import com.airlock.iam.plugin.api.annotation.property.FileProperty;
import com.airlock.iam.plugin.api.annotation.property.PluginListProperty;
import com.airlock.iam.plugin.api.annotation.property.StringProperty;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.config.Environment;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.api.exception.ConfigurationException;
import com.airlock.iam.plugin.api.exception.InitializeException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.valuereader.StringPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.io.File;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Strings;

@Plugin(
   description = "Defines a log file to be viewed. The file name is relative to the current directory or an absolute path name. The underlying log file loader also looks for rotated log files by adding .N to the file name.  (Where N is a whole number starting with 1). This works for example with the rolling file appender of Log4J.",
   displayName = "Log File"
)
public class LogFile {
   public static final String LOG_FILE_DISPLAY_NAME = "Log File";
   private static final String CHARSET_PLATFORM_DEFAULT = "PLATFORM_DEFAULT";
   @StringProperty(
      description = "Defines the translation key for the logfile name. The translations must be provided in the string_XX.properties. ",
      suggestedValues = {"logViewer.usertrail.name", "logViewer.login-app.name", "logViewer.admin-app.name", "logViewer.servicecontainer-app.name"},
      optional = false
   )
   private String nameTranslationKey;
   @FileProperty(
      description = "The path to the log file.",
      optional = false,
      assureExistence = false,
      exampleValues = {
            "instances/XYZ/logs/medusa-usertrail.log",
            "instances/XYZ/logs/adminapp-parsable.log",
            "instances/XYZ/logs/loginapp-parsable.log",
            "instances/XYZ/logs/transaction-approval-parsable.log",
            "instances/XYZ/logs/api-policy-service-parsable.log",
            "instances/XYZ/logs/servicecontainerapp-parsable.log"
      }
   )
   private File file;
   @StringProperty(
      description = "The file encoding of the logfile. If left unconfigured the UTF-8 encoding (matching the Airlock IAM default logger configuration) is used.<p>Set to PLATFORM_DEFAULT to use the platform's default encoding.</p>",
      optional = true,
      suggestedValues = {"UTF-8", "ISO-8859-1", "windows-1252", "PLATFORM_DEFAULT"},
      defaultValue = "UTF-8"
   )
   private String encoding;
   @PluginListProperty(description = "A set of predefined filter patterns can be defined per logfile.", optional = true)
   private List<FilterPattern> filterPatterns;
   private Charset charset;

   public LogFile(String nameTranslationKey, File file, String encoding, List<FilterPattern> filterPatterns) {
      this.nameTranslationKey = nameTranslationKey;
      this.file = file;
      this.encoding = encoding;
      this.filterPatterns = filterPatterns;
   }

   public List<FilterPattern> getFilterPatterns() {
      return this.filterPatterns;
   }

   @Nullable
   public FilterPattern getFilterPatternByNameTranslationKey(String key) {
      for (FilterPattern pattern : this.filterPatterns) {
         if (Strings.CS.equals(key, pattern.getNameTranslationKey())) {
            return pattern;
         }
      }

      return null;
   }

   public File getFile() {
      return this.file;
   }

   public String getNameTranslationKey() {
      return this.nameTranslationKey;
   }

   public Charset getCharset() {
      return this.charset != null ? this.charset : Charset.defaultCharset();
   }

   @AfterConfigActivation
   void afterConfigActivation() throws InitializeException {
      String e = StringUtils.trimToNull(this.encoding);
      if (e != null && !"PLATFORM_DEFAULT".equals(e)) {
         try {
            this.charset = Charset.forName(e);
         } catch (IllegalCharsetNameException ex) {
            throw new InitializeException("illegal charset name: " + e);
         } catch (UnsupportedCharsetException ex) {
            throw new InitializeException("unsupported charset: " + e);
         }
      } else {
         this.charset = Charset.defaultCharset();
      }
   }

   @ConfigurationValidator
   public static void validateConfig(PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment valenv) throws ConfigurationException {
      String encodingStr = StringUtils.trimToNull(StringPropertyValueReader.effectiveStringConfigValue(config, "encoding", env, context));
      if (encodingStr != null && !"PLATFORM_DEFAULT".equals(encodingStr)) {
         try {
            Charset.forName(encodingStr);
         } catch (IllegalCharsetNameException ex) {
            throw new PropertyConstraintViolationException("encoding", config, env, context, "illegal file encoding name: " + encodingStr);
         } catch (UnsupportedCharsetException ex) {
            throw new PropertyConstraintViolationException("encoding", config, env, context, "unsupported file encoding: " + encodingStr);
         }
      }
   }

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

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

   @SuppressFBWarnings(justification = "generated code")
   public static class LogFileBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String nameTranslationKey;
      @SuppressFBWarnings(justification = "generated code")
      private File file;
      @SuppressFBWarnings(justification = "generated code")
      private String encoding;
      @SuppressFBWarnings(justification = "generated code")
      private List<FilterPattern> filterPatterns;

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

      @SuppressFBWarnings(justification = "generated code")
      public LogFile.LogFileBuilder nameTranslationKey(String nameTranslationKey) {
         this.nameTranslationKey = nameTranslationKey;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LogFile.LogFileBuilder file(File file) {
         this.file = file;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LogFile.LogFileBuilder encoding(String encoding) {
         this.encoding = encoding;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LogFile.LogFileBuilder filterPatterns(List<FilterPattern> filterPatterns) {
         this.filterPatterns = filterPatterns;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public LogFile build() {
         return new LogFile(this.nameTranslationKey, this.file, this.encoding, this.filterPatterns);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "LogFile.LogFileBuilder(nameTranslationKey="
            + this.nameTranslationKey
            + ", file="
            + this.file
            + ", encoding="
            + this.encoding
            + ", filterPatterns="
            + this.filterPatterns
            + ")";
      }
   }
}
