import { writePerformanceLog } from '../utils/writePerformanceLog.js';
import { generateOperationId, getScenePerformanceTracker } from './ScenePerformanceTracker.js';
import { PanelProfilingManager } from './PanelProfilingManager.js';
import { LongFrameDetector } from './LongFrameDetector.js';

var __typeError$1 = (msg) => {
  throw TypeError(msg);
};
var __accessCheck$1 = (obj, member, msg) => member.has(obj) || __typeError$1("Cannot " + msg);
var __privateGet$1 = (obj, member, getter) => (__accessCheck$1(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
var __privateAdd$1 = (obj, member, value) => member.has(obj) ? __typeError$1("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
var __privateSet$1 = (obj, member, value, setter) => (__accessCheck$1(obj, member, "write to private field"), member.set(obj, value), value);
var __privateWrapper = (obj, member, setter, getter) => ({
  set _(value) {
    __privateSet$1(obj, member, value);
  },
  get _() {
    return __privateGet$1(obj, member, getter);
  }
});
var _profileInProgress, _interactionInProgress, _profileStartTs, _trailAnimationFrameId, _currentOperationId, _recordedTrailingSpans, _longFrameDetector, _longFramesCount, _longFramesTotalTime, _visibilityChangeHandler, _onInteractionComplete;
const POST_STORM_WINDOW = 2e3;
const DEFAULT_LONG_FRAME_THRESHOLD = 30;
class SceneRenderProfiler {
  constructor(panelProfilingConfig) {
    __privateAdd$1(this, _profileInProgress, null);
    __privateAdd$1(this, _interactionInProgress, null);
    __privateAdd$1(this, _profileStartTs, null);
    __privateAdd$1(this, _trailAnimationFrameId, null);
    // Generic metadata for observer notifications
    this.metadata = {};
    // Operation ID for correlating dashboard interaction events
    __privateAdd$1(this, _currentOperationId);
    // Trailing frame measurements
    __privateAdd$1(this, _recordedTrailingSpans, []);
    // Long frame tracking
    __privateAdd$1(this, _longFrameDetector);
    __privateAdd$1(this, _longFramesCount, 0);
    __privateAdd$1(this, _longFramesTotalTime, 0);
    __privateAdd$1(this, _visibilityChangeHandler, null);
    __privateAdd$1(this, _onInteractionComplete, null);
    this.measureTrailingFrames = (measurementStartTs, lastFrameTime, profileStartTs) => {
      const currentFrameTime = performance.now();
      const frameLength = currentFrameTime - lastFrameTime;
      __privateGet$1(this, _recordedTrailingSpans).push(frameLength);
      if (currentFrameTime - measurementStartTs < POST_STORM_WINDOW) {
        if (__privateGet$1(this, _profileInProgress)) {
          __privateSet$1(this, _trailAnimationFrameId, requestAnimationFrame(
            () => this.measureTrailingFrames(measurementStartTs, currentFrameTime, profileStartTs)
          ));
        }
      } else {
        const slowFrames = processRecordedSpans(__privateGet$1(this, _recordedTrailingSpans));
        const slowFramesTime = slowFrames.reduce((acc, val) => acc + val, 0);
        writePerformanceLog(
          "SRP",
          "Profile tail recorded, slow frames duration:",
          slowFramesTime,
          slowFrames,
          __privateGet$1(this, _profileInProgress)
        );
        __privateSet$1(this, _recordedTrailingSpans, []);
        const profileDuration = measurementStartTs - profileStartTs;
        const slowFrameSummary = slowFrames.length > 0 ? `${slowFramesTime.toFixed(1)}ms slow frames[tail recording] (${slowFrames.length}) \u26A0\uFE0F` : `${slowFramesTime.toFixed(1)}ms slow frames[tail recording] (${slowFrames.length})`;
        const longFrameSummary = __privateGet$1(this, _longFramesCount) > 0 ? `${__privateGet$1(this, _longFramesTotalTime).toFixed(1)}ms long frames[LoAF] (${__privateGet$1(this, _longFramesCount)}) \u26A0\uFE0F` : `${__privateGet$1(this, _longFramesTotalTime).toFixed(1)}ms long frames[LoAF] (${__privateGet$1(this, _longFramesCount)})`;
        writePerformanceLog(
          "SRP",
          `[PROFILER] Complete: ${(profileDuration + slowFramesTime).toFixed(
            1
          )}ms total | ${slowFrameSummary} | ${longFrameSummary}`
        );
        __privateGet$1(this, _longFrameDetector).stop();
        __privateSet$1(this, _trailAnimationFrameId, null);
        const profileEndTs = profileStartTs + profileDuration + slowFramesTime;
        if (!__privateGet$1(this, _profileInProgress)) {
          return;
        }
        const networkDuration = captureNetwork(profileStartTs, profileEndTs);
        if (__privateGet$1(this, _profileInProgress)) {
          const dashboardData = {
            operationId: __privateGet$1(this, _currentOperationId) || generateOperationId("dashboard-fallback"),
            interactionType: __privateGet$1(this, _profileInProgress).origin,
            timestamp: profileEndTs,
            duration: profileDuration + slowFramesTime,
            networkDuration,
            longFramesCount: __privateGet$1(this, _longFramesCount),
            longFramesTotalTime: __privateGet$1(this, _longFramesTotalTime),
            metadata: this.metadata
          };
          const tracker = getScenePerformanceTracker();
          tracker.notifyDashboardInteractionComplete(dashboardData);
          __privateSet$1(this, _profileInProgress, null);
          __privateSet$1(this, _trailAnimationFrameId, null);
        }
      }
    };
    __privateSet$1(this, _longFrameDetector, new LongFrameDetector());
    this.setupVisibilityChangeHandler();
    __privateSet$1(this, _interactionInProgress, null);
    if (panelProfilingConfig) {
      this._panelProfilingManager = new PanelProfilingManager(panelProfilingConfig);
    }
  }
  /** Set generic metadata for observer notifications */
  setMetadata(metadata) {
    this.metadata = { ...metadata };
  }
  setQueryController(queryController) {
    this.queryController = queryController;
  }
  /** Attach panel profiling to a scene object */
  attachPanelProfiling(sceneObject) {
    var _a;
    (_a = this._panelProfilingManager) == null ? void 0 : _a.attachToScene(sceneObject);
  }
  /** Attach profiler to a specific panel */
  attachProfilerToPanel(panel) {
    var _a;
    writePerformanceLog("SRP", "Attaching profiler to panel", panel.state.key);
    (_a = this._panelProfilingManager) == null ? void 0 : _a.attachProfilerToPanel(panel);
  }
  setInteractionCompleteHandler(handler) {
    __privateSet$1(this, _onInteractionComplete, handler != null ? handler : null);
  }
  setupVisibilityChangeHandler() {
    if (__privateGet$1(this, _visibilityChangeHandler)) {
      return;
    }
    __privateSet$1(this, _visibilityChangeHandler, () => {
      if (document.hidden && __privateGet$1(this, _profileInProgress)) {
        writePerformanceLog("SRP", "Tab became inactive, cancelling profile");
        this.cancelProfile();
      }
    });
    if (typeof document !== "undefined") {
      document.addEventListener("visibilitychange", __privateGet$1(this, _visibilityChangeHandler));
    }
  }
  cleanup() {
    var _a;
    if (__privateGet$1(this, _visibilityChangeHandler) && typeof document !== "undefined") {
      document.removeEventListener("visibilitychange", __privateGet$1(this, _visibilityChangeHandler));
      __privateSet$1(this, _visibilityChangeHandler, null);
    }
    __privateGet$1(this, _longFrameDetector).stop();
    this.cancelProfile();
    (_a = this._panelProfilingManager) == null ? void 0 : _a.cleanup();
  }
  startProfile(name) {
    if (document.hidden) {
      writePerformanceLog("SRP", "Tab is inactive, skipping profile", name);
      return;
    }
    if (__privateGet$1(this, _profileInProgress)) {
      if (__privateGet$1(this, _trailAnimationFrameId)) {
        this.cancelProfile();
        this._startNewProfile(name, true);
      } else {
        this.addCrumb(name);
      }
    } else {
      this._startNewProfile(name);
    }
  }
  startInteraction(interaction) {
    if (__privateGet$1(this, _interactionInProgress)) {
      writePerformanceLog("SRP", "Cancelled interaction:", __privateGet$1(this, _interactionInProgress));
      __privateSet$1(this, _interactionInProgress, null);
    }
    __privateSet$1(this, _interactionInProgress, {
      interaction,
      startTs: performance.now()
    });
    writePerformanceLog("SRP", "Started interaction:", interaction);
  }
  stopInteraction() {
    if (!__privateGet$1(this, _interactionInProgress)) {
      return;
    }
    const endTs = performance.now();
    const interactionDuration = endTs - __privateGet$1(this, _interactionInProgress).startTs;
    const networkDuration = captureNetwork(__privateGet$1(this, _interactionInProgress).startTs, endTs);
    writePerformanceLog(
      "SRP",
      `[INTERACTION] Complete: ${interactionDuration.toFixed(1)}ms total | ${networkDuration.toFixed(1)}ms network`
    );
    if (__privateGet$1(this, _onInteractionComplete) && __privateGet$1(this, _profileInProgress)) {
      __privateGet$1(this, _onInteractionComplete).call(this, {
        origin: __privateGet$1(this, _interactionInProgress).interaction,
        duration: interactionDuration,
        networkDuration,
        startTs: __privateGet$1(this, _interactionInProgress).startTs,
        endTs
      });
    }
    performance.mark(`${__privateGet$1(this, _interactionInProgress).interaction}_start`, {
      startTime: __privateGet$1(this, _interactionInProgress).startTs
    });
    performance.mark(`${__privateGet$1(this, _interactionInProgress).interaction}_end`, {
      startTime: endTs
    });
    performance.measure(
      `Interaction_${__privateGet$1(this, _interactionInProgress).interaction}`,
      `${__privateGet$1(this, _interactionInProgress).interaction}_start`,
      `${__privateGet$1(this, _interactionInProgress).interaction}_end`
    );
    __privateSet$1(this, _interactionInProgress, null);
  }
  getCurrentInteraction() {
    var _a, _b;
    return (_b = (_a = __privateGet$1(this, _interactionInProgress)) == null ? void 0 : _a.interaction) != null ? _b : null;
  }
  /**
   * Start new performance profile
   * @param name - Profile trigger (e.g., 'time_range_change')
   * @param force - True if canceling existing profile, false if starting clean
   */
  _startNewProfile(name, force = false) {
    const profileType = force ? "forced" : "clean";
    writePerformanceLog("SRP", `[PROFILER] ${name} started (${profileType})`);
    __privateSet$1(this, _profileInProgress, { origin: name, crumbs: [] });
    __privateSet$1(this, _profileStartTs, performance.now());
    __privateSet$1(this, _longFramesCount, 0);
    __privateSet$1(this, _longFramesTotalTime, 0);
    __privateSet$1(this, _currentOperationId, generateOperationId("dashboard"));
    getScenePerformanceTracker().notifyDashboardInteractionStart({
      operationId: __privateGet$1(this, _currentOperationId),
      interactionType: name,
      timestamp: __privateGet$1(this, _profileStartTs),
      metadata: this.metadata
    });
    __privateGet$1(this, _longFrameDetector).start((event) => {
      if (!__privateGet$1(this, _profileInProgress) || !__privateGet$1(this, _profileStartTs)) {
        return;
      }
      if (event.timestamp < __privateGet$1(this, _profileStartTs)) {
        return;
      }
      __privateWrapper(this, _longFramesCount)._++;
      __privateSet$1(this, _longFramesTotalTime, __privateGet$1(this, _longFramesTotalTime) + event.duration);
    });
  }
  recordProfileTail(measurementStartTime, profileStartTs) {
    __privateSet$1(this, _trailAnimationFrameId, requestAnimationFrame(
      () => this.measureTrailingFrames(measurementStartTime, measurementStartTime, profileStartTs)
    ));
  }
  tryCompletingProfile() {
    var _a;
    writePerformanceLog("SRP", "Trying to complete profile", __privateGet$1(this, _profileInProgress));
    if (((_a = this.queryController) == null ? void 0 : _a.runningQueriesCount()) === 0 && __privateGet$1(this, _profileInProgress)) {
      writePerformanceLog("SRP", "All queries completed, stopping profile");
      this.recordProfileTail(performance.now(), __privateGet$1(this, _profileStartTs));
    }
  }
  isTailRecording() {
    return Boolean(__privateGet$1(this, _trailAnimationFrameId));
  }
  cancelTailRecording() {
    if (__privateGet$1(this, _trailAnimationFrameId)) {
      cancelAnimationFrame(__privateGet$1(this, _trailAnimationFrameId));
      __privateSet$1(this, _trailAnimationFrameId, null);
      writePerformanceLog("SRP", "Cancelled recording frames, new profile started");
    }
  }
  cancelProfile() {
    if (__privateGet$1(this, _profileInProgress)) {
      writePerformanceLog("SRP", "Cancelling profile", __privateGet$1(this, _profileInProgress));
      __privateSet$1(this, _profileInProgress, null);
      if (__privateGet$1(this, _trailAnimationFrameId)) {
        cancelAnimationFrame(__privateGet$1(this, _trailAnimationFrameId));
        __privateSet$1(this, _trailAnimationFrameId, null);
      }
      __privateGet$1(this, _longFrameDetector).stop();
      writePerformanceLog("SRP", "Stopped long frame detection - profile cancelled");
      __privateSet$1(this, _recordedTrailingSpans, []);
      __privateSet$1(this, _longFramesCount, 0);
      __privateSet$1(this, _longFramesTotalTime, 0);
    }
  }
  addCrumb(crumb) {
    if (__privateGet$1(this, _profileInProgress)) {
      getScenePerformanceTracker().notifyDashboardInteractionMilestone({
        operationId: generateOperationId("dashboard-milestone"),
        interactionType: __privateGet$1(this, _profileInProgress).origin,
        timestamp: performance.now(),
        milestone: crumb,
        metadata: this.metadata
      });
      __privateGet$1(this, _profileInProgress).crumbs.push(crumb);
    }
  }
}
_profileInProgress = new WeakMap();
_interactionInProgress = new WeakMap();
_profileStartTs = new WeakMap();
_trailAnimationFrameId = new WeakMap();
_currentOperationId = new WeakMap();
_recordedTrailingSpans = new WeakMap();
_longFrameDetector = new WeakMap();
_longFramesCount = new WeakMap();
_longFramesTotalTime = new WeakMap();
_visibilityChangeHandler = new WeakMap();
_onInteractionComplete = new WeakMap();
function processRecordedSpans(spans) {
  for (let i = spans.length - 1; i >= 0; i--) {
    if (spans[i] > DEFAULT_LONG_FRAME_THRESHOLD) {
      return spans.slice(0, i + 1);
    }
  }
  return [spans[0]];
}
function captureNetwork(startTs, endTs) {
  const entries = performance.getEntriesByType("resource");
  performance.clearResourceTimings();
  const networkEntries = entries.filter(
    (entry) => entry.startTime >= startTs && entry.startTime <= endTs && entry.responseEnd >= startTs && entry.responseEnd <= endTs
  );
  for (const entry of networkEntries) {
    performance.measure("Network entry " + entry.name, {
      start: entry.startTime,
      end: entry.responseEnd
    });
  }
  return calculateNetworkTime(networkEntries);
}
function calculateNetworkTime(requests) {
  if (requests.length === 0) {
    return 0;
  }
  requests.sort((a, b) => a.startTime - b.startTime);
  let totalNetworkTime = 0;
  let currentStart = requests[0].startTime;
  let currentEnd = requests[0].responseEnd;
  for (let i = 1; i < requests.length; i++) {
    if (requests[i].startTime <= currentEnd) {
      currentEnd = Math.max(currentEnd, requests[i].responseEnd);
    } else {
      totalNetworkTime += currentEnd - currentStart;
      currentStart = requests[i].startTime;
      currentEnd = requests[i].responseEnd;
    }
  }
  totalNetworkTime += currentEnd - currentStart;
  return totalNetworkTime;
}

export { SceneRenderProfiler, calculateNetworkTime, captureNetwork, processRecordedSpans };
//# sourceMappingURL=SceneRenderProfiler.js.map
