package tv.pluto.core;

import com.plutotv.test.lib.LogUtils;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;
import tv.pluto.utils.Route;

@Component
public class GrpcChannelManager {
  private static final int MAX_INBOUND_MESSAGE_SIZE = 1024 * 1024 * 1024; // 1GB
  private final ManagedChannel channel;

  public GrpcChannelManager() {
    this.channel =
        ManagedChannelBuilder.forTarget(Route.getGrpcServer())
            .maxInboundMessageSize(MAX_INBOUND_MESSAGE_SIZE)
            .build();
  }

  public ManagedChannel getChannel() {
    return channel;
  }

  @PreDestroy
  public void shutdown() {
    LogUtils.logInfoMessage("Shutting down gRPC channel.");
    if (channel != null) {
      if (!channel.isShutdown()) {
        channel.shutdown();
        try {
          LogUtils.logInfoMessage("Awaiting termination of gRPC channel.");
          if (channel.awaitTermination(5, TimeUnit.SECONDS)) {
            LogUtils.logInfoMessage("gRPC channel terminated successfully.");
          } else {
            LogUtils.logSevereMessage("gRPC channel termination timed out. Forcing shutdown.");
            channel.shutdownNow();
          }
        } catch (InterruptedException e) {
          LogUtils.logSevereMessage("gRPC channel termination interrupted: " + e.getMessage());
          Thread.currentThread().interrupt();
          channel.shutdownNow();
        }
      } else {
        LogUtils.logInfoMessage("gRPC channel already shut down.");
      }
    } else {
      LogUtils.logInfoMessage("gRPC channel is null.");
    }
  }

  @PostConstruct
  public void init() {
    LogUtils.logInfoMessage("Adding shutdown hook for gRPC channel.");
    Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
  }
}
