package org.testcontainers.utility;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.dockerjava.api.command.DockerCmd;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.slf4j.MDC;

import java.util.List;

/**
 * Logger for tracking potentially destructive actions, intended for usage in a shared Docker environment where
 * traceability is needed. This class uses SLF4J, logging at TRACE level and capturing common fields as MDC fields.
 * <p>
 * Users should configure their test logging to apply appropriate filters/storage so that these logs are
 * captured appropriately.
 */
@Slf4j
@UtilityClass
public class AuditLogger {

    private static final ObjectMapper objectMapper = new ObjectMapper();
    public static final String MDC_PREFIX = AuditLogger.class.getCanonicalName();

    public static void doLog(String action, String image, String containerId, DockerCmd<?> cmd) {
        doLog(action, image, containerId, cmd, null);
    }

    public static void doLog(String action, String image, String containerId, DockerCmd<?> cmd, @Nullable Exception e) {
        MDC.put(MDC_PREFIX + ".Action", action);
        MDC.put(MDC_PREFIX + ".Image", image);
        MDC.put(MDC_PREFIX + ".ContainerId", containerId);
        try {
            MDC.put(MDC_PREFIX + ".Command", objectMapper.writeValueAsString(cmd));
        } catch (JsonProcessingException ignored) {
        }

        if (e != null) {
            MDC.put(MDC_PREFIX + ".Exception", e.getLocalizedMessage());
            log.trace("{} action with image: {}, containerId: {}", action, image, containerId, e);
        } else {
            log.trace("{} action with image: {}, containerId: {}", action, image, containerId);
        }

        MDC.remove(MDC_PREFIX + ".Action");
        MDC.remove(MDC_PREFIX + ".Image");
        MDC.remove(MDC_PREFIX + ".ContainerId");
        MDC.remove(MDC_PREFIX + ".Command");
        MDC.remove(MDC_PREFIX + ".Exception");
    }

    public static void doComposeLog(String[] commandParts, List<String> env) {
        MDC.put(MDC_PREFIX + ".Action", "COMPOSE");
        final String command = StringUtils.join(commandParts, ' ');
        MDC.put(MDC_PREFIX + ".Compose.Command", command);
        MDC.put(MDC_PREFIX + ".Compose.Env", env.toString());

        log.trace("COMPOSE action with command: {}, env: {}", command, env);

        MDC.remove(MDC_PREFIX + ".Action");
        MDC.remove(MDC_PREFIX + ".Compose.Command");
        MDC.remove(MDC_PREFIX + ".Compose.Env");
    }
}

@@ -312,16 +312,58 @@
 gUtils;%0A
+import org.jetbrains.annotations.NotNull;%0A
 import o
@@ -444,16 +444,75 @@
 .List;%0A%0A
+import static com.google.common.base.Strings.nullToEmpty;%0A%0A
 /**%0A * L
@@ -1104,32 +1104,41 @@
 atic void doLog(
+@NotNull 
 String action, S
@@ -1139,42 +1139,158 @@
 ion,
- String image, String containerId,
+%0A                             @Nullable String image,%0A                             @Nullable String containerId,%0A                             @NotNull
  Doc
@@ -1302,24 +1302,25 @@
 d%3C?%3E cmd) %7B%0A
+%0A
         doLo
@@ -1393,24 +1393,33 @@
  void doLog(
+@NotNull 
 String actio
@@ -1424,85 +1424,300 @@
 ion,
- String image, String containerId, DockerCmd%3C?%3E cmd, @Nullable Exception e) %7B
+%0A                             @Nullable String image,%0A                             @Nullable String containerId,%0A                             @NotNull DockerCmd%3C?%3E cmd,%0A                             @Nullable Exception e) %7B%0A%0A        if (! log.isTraceEnabled()) %7B%0A            return;%0A        %7D%0A
 %0A   
@@ -1757,15 +1757,28 @@
 n%22, 
+nullToEmpty(
 action)
+)
 ;%0A  
@@ -1818,14 +1818,27 @@
 e%22, 
+nullToEmpty(
 image)
+)
 ;%0A  
@@ -1880,16 +1880,28 @@
 nerId%22, 
+nullToEmpty(
 containe
@@ -1896,33 +1896,35 @@
 pty(containerId)
-;
+);%0A
 %0A        try %7B%0A 
@@ -2661,16 +2661,25 @@
 poseLog(
+@NotNull 
 String%5B%5D
@@ -2696,80 +2696,301 @@
 rts,
- List%3CString%3E env) %7B%0A        MDC.put(MDC_PREFIX + %22.Action%22, %22COMPOSE%22);
+%0A                                    @Nullable List%3CString%3E env) %7B%0A%0A        if (! log.isTraceEnabled()) %7B%0A            return;%0A        %7D%0A%0A        MDC.put(MDC_PREFIX + %22.Action%22, %22COMPOSE%22);%0A%0A        if (env != null) %7B%0A            MDC.put(MDC_PREFIX + %22.Compose.Env%22, env.toString());%0A        %7D%0A
 %0A   
@@ -3116,70 +3116,8 @@
 nd);
-%0A        MDC.put(MDC_PREFIX + %22.Compose.Env%22, env.toString());
 %0A%0A  

Add additional guards for cases where AuditLogger params may be null (#370)