package com.airlock.iam.application.webserver.infrastructure.health;

import java.lang.management.ManagementFactory;
import java.time.Instant;
import java.util.Optional;
import java.util.Set;
import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;

public final class WebModuleCheck implements HealthCheck {
   private final String identifier;
   private final String path;
   private final MBeanServer mBeanServer;

   public WebModuleCheck(String identifier, String path) {
      this.identifier = identifier;
      this.path = path;
      this.mBeanServer = ManagementFactory.getPlatformMBeanServer();
   }

   public HealthCheckResponse call() {
      try {
         return this.getWebModuleObjectName().map(this::checkWebModule).orElseGet(this::down);
      } catch (MalformedObjectNameException e) {
         return this.down();
      }
   }

   private Optional<ObjectName> getWebModuleObjectName() throws MalformedObjectNameException {
      Set<ObjectName> webModules = this.mBeanServer.queryNames(new ObjectName("*:j2eeType=WebModule,*"), null);
      return webModules.stream().filter(object -> object.getKeyProperty("name").endsWith(this.path)).findFirst();
   }

   private HealthCheckResponse checkWebModule(ObjectName webModule) {
      try {
         String webModuleState = (String)this.mBeanServer.getAttribute(webModule, "stateName");
         return HealthCheckResponse.named(this.identifier)
            .status("STARTED".equals(webModuleState))
            .withData("startTime", formatTimestamp((Long)this.mBeanServer.getAttribute(webModule, "startTime")))
            .withData("startupTime", (Long)this.mBeanServer.getAttribute(webModule, "startupTime"))
            .withData("requestCount", ((Integer)this.mBeanServer.getAttribute(webModule, "requestCount")).intValue())
            .withData("processingTime", (Long)this.mBeanServer.getAttribute(webModule, "processingTime"))
            .build();
      } catch (JMException e) {
         return this.down();
      }
   }

   private HealthCheckResponse down() {
      return HealthCheckResponse.named(this.identifier).down().build();
   }

   private static String formatTimestamp(long timestamp) {
      return Instant.ofEpochMilli(timestamp).toString();
   }
}
