// 
// Decompiled by Procyon v0.6.0
// 

package io.sentry.util;

import java.util.Collection;
import io.sentry.protocol.SentryStackFrame;
import java.util.ArrayList;
import io.sentry.protocol.SentryStackTrace;
import java.util.Iterator;
import io.sentry.protocol.SentryThread;
import io.sentry.protocol.SentryException;
import io.sentry.Breadcrumb;
import java.util.List;
import io.sentry.JsonSerializable;
import org.jetbrains.annotations.Nullable;
import io.sentry.SentryLevel;
import io.sentry.SentryOptions;
import io.sentry.Hint;
import org.jetbrains.annotations.NotNull;
import io.sentry.SentryEvent;
import org.jetbrains.annotations.ApiStatus;

@ApiStatus.Internal
public final class EventSizeLimitingUtils
{
    private static final long MAX_EVENT_SIZE_BYTES = 1048576L;
    private static final int MAX_FRAMES_PER_STACK = 500;
    private static final int FRAMES_PER_SIDE = 250;
    
    private EventSizeLimitingUtils() {
    }
    
    @Nullable
    public static SentryEvent limitEventSize(@NotNull final SentryEvent event, @NotNull final Hint hint, @NotNull final SentryOptions options) {
        try {
            if (!options.isEnableEventSizeLimiting()) {
                return event;
            }
            if (isSizeOk(event, options)) {
                return event;
            }
            options.getLogger().log(SentryLevel.INFO, "Event %s exceeds %d bytes limit. Reducing size by dropping fields.", event.getEventId(), 1048576L);
            SentryEvent reducedEvent = event;
            final SentryOptions.OnOversizedEventCallback callback = options.getOnOversizedEvent();
            if (callback != null) {
                try {
                    reducedEvent = callback.execute(reducedEvent, hint);
                    if (isSizeOk(reducedEvent, options)) {
                        return reducedEvent;
                    }
                }
                catch (final Throwable e) {
                    options.getLogger().log(SentryLevel.ERROR, "The onOversizedEvent callback threw an exception. It will be ignored and automatic reduction will continue.", e);
                    reducedEvent = event;
                }
            }
            reducedEvent = removeAllBreadcrumbs(reducedEvent, options);
            if (isSizeOk(reducedEvent, options)) {
                return reducedEvent;
            }
            reducedEvent = truncateStackFrames(reducedEvent, options);
            if (!isSizeOk(reducedEvent, options)) {
                options.getLogger().log(SentryLevel.WARNING, "Event %s still exceeds size limit after reducing all fields. Event may be rejected by server.", event.getEventId());
            }
            return reducedEvent;
        }
        catch (final Throwable e2) {
            options.getLogger().log(SentryLevel.ERROR, "An error occurred while limiting event size. Event will be sent as-is.", e2);
            return event;
        }
    }
    
    private static boolean isSizeOk(@NotNull final SentryEvent event, @NotNull final SentryOptions options) {
        final long size = JsonSerializationUtils.byteSizeOf(options.getSerializer(), options.getLogger(), event);
        return size <= 1048576L;
    }
    
    @NotNull
    private static SentryEvent removeAllBreadcrumbs(@NotNull final SentryEvent event, @NotNull final SentryOptions options) {
        final List<Breadcrumb> breadcrumbs = event.getBreadcrumbs();
        if (breadcrumbs != null && !breadcrumbs.isEmpty()) {
            event.setBreadcrumbs(null);
            options.getLogger().log(SentryLevel.DEBUG, "Removed breadcrumbs to reduce size of event %s", event.getEventId());
        }
        return event;
    }
    
    @NotNull
    private static SentryEvent truncateStackFrames(@NotNull final SentryEvent event, @NotNull final SentryOptions options) {
        final List<SentryException> exceptions = event.getExceptions();
        if (exceptions != null) {
            for (final SentryException exception : exceptions) {
                final SentryStackTrace stacktrace = exception.getStacktrace();
                if (stacktrace != null) {
                    truncateStackFramesInStackTrace(stacktrace, event, options, "Truncated exception stack frames of event %s");
                }
            }
        }
        final List<SentryThread> threads = event.getThreads();
        if (threads != null) {
            for (final SentryThread thread : threads) {
                final SentryStackTrace stacktrace2 = thread.getStacktrace();
                if (stacktrace2 != null) {
                    truncateStackFramesInStackTrace(stacktrace2, event, options, "Truncated thread stack frames for event %s");
                }
            }
        }
        return event;
    }
    
    private static void truncateStackFramesInStackTrace(@NotNull final SentryStackTrace stacktrace, @NotNull final SentryEvent event, @NotNull final SentryOptions options, @NotNull final String logMessage) {
        final List<SentryStackFrame> frames = stacktrace.getFrames();
        if (frames != null && frames.size() > 500) {
            final List<SentryStackFrame> truncatedFrames = new ArrayList<SentryStackFrame>(500);
            truncatedFrames.addAll(frames.subList(0, 250));
            truncatedFrames.addAll(frames.subList(frames.size() - 250, frames.size()));
            stacktrace.setFrames(truncatedFrames);
            options.getLogger().log(SentryLevel.DEBUG, logMessage, event.getEventId());
        }
    }
}
