/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package org.apache.geode.metrics.internal;

import static java.util.Objects.requireNonNull;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
import org.apache.logging.log4j.Logger;

import org.apache.geode.annotations.VisibleForTesting;
import org.apache.geode.distributed.Locator;
import org.apache.geode.distributed.ServerLauncher;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.internal.util.CollectingServiceLoader;
import org.apache.geode.internal.util.ListCollectingServiceLoader;
import org.apache.geode.logging.internal.log4j.api.LogService;
import org.apache.geode.metrics.MetricsPublishingService;

/**
 * Manages metrics on behalf of an {@code InternalDistributedSystem}.
 * This metrics service uses a composite meter registry to manage meters, client-supplied
 * meter registries, and metrics publishing services.
 * <p>
 * Each meter added to this metrics service's meter registry gains these common tags:
 * </p>
 * <ul>
 * <li><em>member</em>: The name of the system.</li>
 * <li><em>host</em>: The name of the host on which the system is running.</li>
 * <li><em>cluster</em>: The ID of the cluster that includes the system.
 * This tag is omitted if the system is a client.
 * </li>
 * </ul>
 */
public class InternalDistributedSystemMetricsService implements MetricsService {
  private final Logger logger;
  private final CompositeMeterRegistry meterRegistry;
  private final CollectingServiceLoader<MetricsPublishingService> publishingServiceLoader;
  private final Collection<MetricsPublishingService> publishingServices = new ArrayList<>();
  private final CloseableMeterBinder binder;
  private final Set<MeterRegistry> persistentMeterRegistries = new HashSet<>();
  private final MetricsService.Builder builder;

  @FunctionalInterface
  @VisibleForTesting
  interface Factory {
    MetricsService create(MetricsService.Builder builder, Logger logger,
        CollectingServiceLoader<MetricsPublishingService> publishingServiceLoader,
        CompositeMeterRegistry metricsServiceMeterRegistry,
        Collection<MeterRegistry> persistentMeterRegistries, CloseableMeterBinder binder,
        InternalDistributedSystem system, boolean isClient, boolean hasLocator,
        boolean hasCacheServer);
  }

  @VisibleForTesting
  InternalDistributedSystemMetricsService(MetricsService.Builder builder, Logger logger,
      CollectingServiceLoader<MetricsPublishingService> publishingServiceLoader,
      CompositeMeterRegistry metricsServiceMeterRegistry,
      Collection<MeterRegistry> persistentMeterRegistries, CloseableMeterBinder binder,
      InternalDistributedSystem system, boolean isClient, boolean hasLocator,
      boolean hasCacheServer) {
    this.builder = builder;
    this.logger = logger;
    this.meterRegistry = metricsServiceMeterRegistry;
    this.publishingServiceLoader = publishingServiceLoader;
    this.binder = binder;
    this.persistentMeterRegistries.addAll(persistentMeterRegistries);
    addCommonTags(system, isClient, hasLocator, hasCacheServer);
  }

  /**
   * Starts this metrics service. The service remains active until {@code stop()} is called.
   * <p>
   * This method configures the service's meter registry with:
   * <ul>
   * <li>a set of standard process, system, and JVM meters</li>
   * </ul>
   *
   * This method also loads and starts each {@link MetricsPublishingService} found on the classpath.
   */
  @Override
  public void start() {
    persistentMeterRegistries.forEach(meterRegistry::add);

    binder.bindTo(meterRegistry);

    publishingServices.addAll(publishingServiceLoader.loadServices(MetricsPublishingService.class));
    publishingServices.forEach(this::startMetricsPublishingService);
  }

  /**
   * Returns this metrics service's meter registry.
   *
   * @return this metrics service's meter registry
   */
  @Override
  public MeterRegistry getMeterRegistry() {
    return meterRegistry;
  }

  @Override
  public MetricsService.Builder getRebuilder() {
    return builder;
  }

  /**
   * Stops all publishing services and closes this metrics service's meter registry. This method
   * removes from the metrics service all client meter registries and all registries added by
   * publishing services. This method does not close any client meter registry or any registry
   * added to this metrics service by publishing services.
   * <p>
   * After this method returns, this metrics service is no longer active, and its meter registry is
   * closed.
   */
  @Override
  public void stop() {
    closeMeterBinder();
    clearAndCloseMeterRegistry();
  }

  @Override
  public void addSubregistry(MeterRegistry subregistry) {
    meterRegistry.add(subregistry);
  }

  @Override
  public void removeSubregistry(MeterRegistry subregistry) {
    meterRegistry.remove(subregistry);
  }

  private void addCommonTags(InternalDistributedSystem system, boolean isClient,
      boolean hasLocators, boolean hasCacheServer) {
    int clusterId = system.getConfig().getDistributedSystemId();

    String memberName = system.getName();
    String hostName = system.getDistributedMember().getHost();

    requireNonNull(memberName, "Member Name is null.");
    requireNonNull(hostName, "Host Name is null.");

    if (hostName.isEmpty()) {
      throw new IllegalArgumentException("Host name must not be empty");
    }
    Set<Tag> tags = new HashSet<>();

    if (!isClient) {
      tags.add(Tag.of("cluster", String.valueOf(clusterId)));

    }

    if (!memberName.isEmpty()) {
      tags.add(Tag.of("member", memberName));
    }

    tags.add(Tag.of("host", hostName));
    tags.add(Tag.of("member.type", memberTypeFor(hasLocators, hasCacheServer)));
    meterRegistry.config().commonTags(tags);
  }

  private static String memberTypeFor(boolean hasLocator, boolean hasCacheServer) {
    if (hasCacheServer && hasLocator) {
      return "server-locator";
    }

    if (hasCacheServer) {
      return "server";
    }

    if (hasLocator) {
      return "locator";
    }

    return "embedded-cache";
  }

  private void startMetricsPublishingService(MetricsPublishingService service) {
    try {
      service.start(this);
    } catch (Exception thrown) {
      logger.error("Exception while starting metrics publishing service "
          + service.getClass().getName(), thrown);
    }
  }

  private void stopMetricsPublishingService(MetricsPublishingService service) {
    try {
      service.stop(this);
    } catch (Exception thrown) {
      logger.error("Exception while stopping metrics publishing service "
          + service.getClass().getName(), thrown);
    }
  }

  private void closeMeterBinder() {
    try {
      binder.close();
    } catch (Exception ignored) {
      // Nothing to do, because the standard meter binder catches and logs all exceptions
    }
  }

  private void clearAndCloseMeterRegistry() {
    if (meterRegistry != null) {
      publishingServices.forEach(this::stopMetricsPublishingService);
      publishingServices.clear();

      new HashSet<>(meterRegistry.getRegistries())
          .forEach(meterRegistry::remove);

      meterRegistry.close();
    }
  }

  public static class Builder implements MetricsService.Builder {
    private boolean isClient = false;
    private Supplier<Logger> loggerSupplier = LogService::getLogger;
    private Supplier<CloseableMeterBinder> meterBinderSupplier = StandardMeterBinder::new;
    private Factory metricsServiceFactory = InternalDistributedSystemMetricsService::new;
    private Supplier<CompositeMeterRegistry> compositeRegistrySupplier =
        CompositeMeterRegistry::new;
    private Supplier<CollectingServiceLoader<MetricsPublishingService>> serviceLoaderSupplier =
        ListCollectingServiceLoader::new;
    private Set<MeterRegistry> persistentMeterRegistries = new HashSet<>();
    private BooleanSupplier hasLocator = Locator::hasLocator;
    private BooleanSupplier hasCacheServer = () -> ServerLauncher.getInstance() != null;

    @Override
    public MetricsService build(InternalDistributedSystem system) {
      return metricsServiceFactory.create(this, loggerSupplier.get(), serviceLoaderSupplier.get(),
          compositeRegistrySupplier.get(), persistentMeterRegistries, meterBinderSupplier.get(),
          system, isClient, hasLocator.getAsBoolean(), hasCacheServer.getAsBoolean());
    }

    @Override
    public Builder addPersistentMeterRegistry(MeterRegistry registry) {
      persistentMeterRegistries.add(registry);
      return this;
    }

    @Override
    public Builder addPersistentMeterRegistries(Collection<MeterRegistry> registries) {
      this.persistentMeterRegistries.addAll(registries);
      return this;
    }

    @Override
    public MetricsService.Builder setIsClient(boolean isClient) {
      this.isClient = isClient;
      return this;
    }

    @VisibleForTesting
    Builder setBinder(CloseableMeterBinder binder) {
      meterBinderSupplier = () -> binder;
      return this;
    }

    @VisibleForTesting
    Builder setCacheServerDetector(BooleanSupplier hasCacheServer) {
      this.hasCacheServer = hasCacheServer;
      return this;
    }

    @VisibleForTesting
    Builder setCompositeMeterRegistry(CompositeMeterRegistry registry) {
      compositeRegistrySupplier = () -> registry;
      return this;
    }

    @VisibleForTesting
    Builder setLocatorDetector(BooleanSupplier hasLocator) {
      this.hasLocator = hasLocator;
      return this;
    }

    @VisibleForTesting
    Builder setLogger(Logger logger) {
      loggerSupplier = () -> logger;
      return this;
    }

    @VisibleForTesting
    Builder setMetricsServiceFactory(Factory factory) {
      metricsServiceFactory = factory;
      return this;
    }

    @VisibleForTesting
    Builder setServiceLoader(CollectingServiceLoader<MetricsPublishingService> serviceLoader) {
      serviceLoaderSupplier = () -> serviceLoader;
      return this;
    }
  }
}
