package io.sentry;

import io.sentry.logger.ILoggerApi;
import io.sentry.logger.NoOpLoggerApi;
import io.sentry.metrics.IMetricsApi;
import io.sentry.metrics.NoOpMetricsApi;
import io.sentry.protocol.Feedback;
import io.sentry.protocol.SentryId;
import io.sentry.protocol.SentryTransaction;
import io.sentry.protocol.User;
import io.sentry.transport.RateLimiter;
import io.sentry.util.LazyEvaluator;
import java.util.List;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class NoOpScopes implements IScopes {

  private static final NoOpScopes instance = new NoOpScopes();

  private final @NotNull LazyEvaluator<SentryOptions> emptyOptions =
      new LazyEvaluator<>(() -> SentryOptions.empty());

  private NoOpScopes() {}

  public static NoOpScopes getInstance() {
    return instance;
  }

  @Override
  public boolean isEnabled() {
    return false;
  }

  @Override
  public @NotNull SentryId captureEvent(@NotNull SentryEvent event, @Nullable Hint hint) {
    return SentryId.EMPTY_ID;
  }

  @Override
  public @NotNull SentryId captureEvent(
      @NotNull SentryEvent event, @Nullable Hint hint, @NotNull ScopeCallback callback) {
    return SentryId.EMPTY_ID;
  }

  @Override
  public @NotNull SentryId captureMessage(@NotNull String message, @NotNull SentryLevel level) {
    return SentryId.EMPTY_ID;
  }

  @Override
  public @NotNull SentryId captureMessage(
      @NotNull String message, @NotNull SentryLevel level, @NotNull ScopeCallback callback) {
    return SentryId.EMPTY_ID;
  }

  @Override
  public @NotNull SentryId captureFeedback(
      @NotNull Feedback feedback, @Nullable Hint hint, @Nullable ScopeCallback callback) {
    return SentryId.EMPTY_ID;
  }

  @Override
  public @NotNull SentryId captureEnvelope(@NotNull SentryEnvelope envelope, @Nullable Hint hint) {
    return SentryId.EMPTY_ID;
  }

  @Override
  public @NotNull SentryId captureException(@NotNull Throwable throwable, @Nullable Hint hint) {
    return SentryId.EMPTY_ID;
  }

  @Override
  public @NotNull SentryId captureException(
      @NotNull Throwable throwable, @Nullable Hint hint, @NotNull ScopeCallback callback) {
    return SentryId.EMPTY_ID;
  }

  @Deprecated
  @Override
  public void captureUserFeedback(@NotNull UserFeedback userFeedback) {}

  @Override
  public void startSession() {}

  @Override
  public void endSession() {}

  @Override
  public void close() {}

  @Override
  public void close(final boolean isRestarting) {}

  @Override
  public void addBreadcrumb(@NotNull Breadcrumb breadcrumb, @Nullable Hint hint) {}

  @Override
  public void addBreadcrumb(final @NotNull Breadcrumb breadcrumb) {}

  @Override
  public void setLevel(@Nullable SentryLevel level) {}

  @Override
  public void setTransaction(@Nullable String transaction) {}

  @Override
  public void setUser(@Nullable User user) {}

  @Override
  public void setFingerprint(@NotNull List<String> fingerprint) {}

  @Override
  public void clearBreadcrumbs() {}

  @Override
  public void setTag(@Nullable String key, @Nullable String value) {}

  @Override
  public void removeTag(@Nullable String key) {}

  @Override
  public void setExtra(@Nullable String key, @Nullable String value) {}

  @Override
  public void removeExtra(@Nullable String key) {}

  @Override
  public @NotNull SentryId getLastEventId() {
    return SentryId.EMPTY_ID;
  }

  @Override
  public @NotNull ISentryLifecycleToken pushScope() {
    return NoOpScopesLifecycleToken.getInstance();
  }

  @Override
  public @NotNull ISentryLifecycleToken pushIsolationScope() {
    return NoOpScopesLifecycleToken.getInstance();
  }

  /**
   * @deprecated please call {@link ISentryLifecycleToken#close()} on the token returned by {@link
   *     IScopes#pushScope()} or {@link IScopes#pushIsolationScope()} instead.
   */
  @Override
  @Deprecated
  public void popScope() {}

  @Override
  public void withScope(@NotNull ScopeCallback callback) {
    callback.run(NoOpScope.getInstance());
  }

  @Override
  public void withIsolationScope(@NotNull ScopeCallback callback) {
    callback.run(NoOpScope.getInstance());
  }

  @Override
  public void configureScope(@Nullable ScopeType scopeType, @NotNull ScopeCallback callback) {}

  @Override
  public void bindClient(@NotNull ISentryClient client) {}

  @Override
  public boolean isHealthy() {
    return true;
  }

  @Override
  public void flush(long timeoutMillis) {}

  /**
   * @deprecated please use {@link IScopes#forkedScopes(String)} or {@link
   *     IScopes#forkedCurrentScope(String)} instead.
   */
  @Deprecated
  @Override
  public @NotNull IHub clone() {
    return NoOpHub.getInstance();
  }

  @Override
  public @NotNull IScopes forkedScopes(@NotNull String creator) {
    return NoOpScopes.getInstance();
  }

  @Override
  public @NotNull IScopes forkedCurrentScope(@NotNull String creator) {
    return NoOpScopes.getInstance();
  }

  @Override
  public @NotNull IScopes forkedRootScopes(final @NotNull String creator) {
    return NoOpScopes.getInstance();
  }

  @Override
  public @NotNull ISentryLifecycleToken makeCurrent() {
    return NoOpScopesLifecycleToken.getInstance();
  }

  @Override
  @ApiStatus.Internal
  public @NotNull IScope getScope() {
    return NoOpScope.getInstance();
  }

  @Override
  @ApiStatus.Internal
  public @NotNull IScope getIsolationScope() {
    return NoOpScope.getInstance();
  }

  @Override
  @ApiStatus.Internal
  public @NotNull IScope getGlobalScope() {
    return NoOpScope.getInstance();
  }

  @Override
  public @Nullable IScopes getParentScopes() {
    return null;
  }

  @Override
  public boolean isAncestorOf(@Nullable IScopes otherScopes) {
    return false;
  }

  @Override
  public @NotNull SentryId captureTransaction(
      final @NotNull SentryTransaction transaction,
      final @Nullable TraceContext traceContext,
      final @Nullable Hint hint,
      final @Nullable ProfilingTraceData profilingTraceData) {
    return SentryId.EMPTY_ID;
  }

  @Override
  public @NotNull SentryId captureProfileChunk(@NotNull ProfileChunk profileChunk) {
    return SentryId.EMPTY_ID;
  }

  @Override
  public @NotNull ITransaction startTransaction(
      @NotNull TransactionContext transactionContext,
      @NotNull TransactionOptions transactionOptions) {
    return NoOpTransaction.getInstance();
  }

  @Override
  public void startProfiler() {}

  @Override
  public void stopProfiler() {}

  @Override
  public void setSpanContext(
      final @NotNull Throwable throwable,
      final @NotNull ISpan spanContext,
      final @NotNull String transactionName) {}

  @Override
  public @Nullable ISpan getSpan() {
    return null;
  }

  @Override
  public void setActiveSpan(final @Nullable ISpan span) {}

  @Override
  public @Nullable ITransaction getTransaction() {
    return null;
  }

  @Override
  public @NotNull SentryOptions getOptions() {
    return emptyOptions.getValue();
  }

  @Override
  public @Nullable Boolean isCrashedLastRun() {
    return null;
  }

  @Override
  public void reportFullyDisplayed() {}

  @Override
  public @Nullable TransactionContext continueTrace(
      final @Nullable String sentryTrace, final @Nullable List<String> baggageHeaders) {
    return null;
  }

  @Override
  public @Nullable SentryTraceHeader getTraceparent() {
    return null;
  }

  @Override
  public @Nullable BaggageHeader getBaggage() {
    return null;
  }

  @Override
  @ApiStatus.Experimental
  public @NotNull SentryId captureCheckIn(final @NotNull CheckIn checkIn) {
    return SentryId.EMPTY_ID;
  }

  @Override
  public @Nullable RateLimiter getRateLimiter() {
    return null;
  }

  @Override
  public boolean isNoOp() {
    return true;
  }

  @Override
  public @NotNull SentryId captureReplay(@NotNull SentryReplayEvent replay, @Nullable Hint hint) {
    return SentryId.EMPTY_ID;
  }

  @Override
  public @NotNull ILoggerApi logger() {
    return NoOpLoggerApi.getInstance();
  }

  @Override
  public @NotNull IMetricsApi metrics() {
    return NoOpMetricsApi.getInstance();
  }

  @Override
  public @NotNull IFeedbackApi feedback() {
    return NoOpFeedbackApi.getInstance();
  }

  @Override
  public void setAttribute(final @Nullable String key, final @Nullable Object value) {}

  @Override
  public void setAttribute(final @Nullable SentryAttribute attribute) {}

  @Override
  public void setAttributes(final @Nullable SentryAttributes attributes) {}

  @Override
  public void removeAttribute(final @Nullable String key) {}

  @Override
  public void addFeatureFlag(final @Nullable String flag, final @Nullable Boolean result) {}
}
