// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import type * as SDK from '../../core/sdk/sdk.js';
import * as Trace from '../../models/trace/trace.js';

import {TracingManager, type TracingManagerClient} from './TracingManager.js';

export class PerformanceTracing implements TracingManagerClient {
  readonly #traceEvents: Object[] = [];
  #tracingManager: TracingManager|null = null;
  #delegate: Delegate;

  constructor(target: SDK.Target.Target, delegate: Delegate) {
    this.#tracingManager = target.model(TracingManager);
    this.#delegate = delegate;
  }

  async start(): Promise<void> {
    this.#traceEvents.length = 0;

    if (!this.#tracingManager) {
      throw new Error('No tracing manager');
    }

    // This panel may be opened with trace data recorded in other tools.
    const categories = [
      '-*',
      ...Trace.Types.Events.DefaultCategories,
      ...Trace.Types.Events.OptionalCategories.JsSampling,
      ...Trace.Types.Events.OptionalCategories.Screenshot,
      ...Trace.Types.Events.OptionalCategories.InvalidationTracking,
      'latencyInfo',
    ].join(',');

    const started = await this.#tracingManager.start(this, categories);

    if (!started) {
      throw new Error('Unable to start tracing.');
    }
  }

  async stop(): Promise<void> {
    return this.#tracingManager?.stop();
  }

  // Start of implementation of SDK.TracingManager.TracingManagerClient
  traceEventsCollected(events: Object[]): void {
    this.#traceEvents.push(...events);
  }

  tracingBufferUsage(usage: number): void {
    this.#delegate.tracingBufferUsage(usage);
  }

  eventsRetrievalProgress(progress: number): void {
    this.#delegate.eventsRetrievalProgress(progress);
  }

  tracingComplete(): void {
    this.#delegate.tracingComplete(this.#traceEvents);
  }
  // End of implementation of SDK.TracingManager.TracingManagerClient
}

interface Delegate {
  tracingBufferUsage(usage: number): void;
  eventsRetrievalProgress(progress: number): void;
  tracingComplete(events: Object[]): void;
}

/** Used by an implementation of Common.Revealer to transfer data from the recorder to the performance panel. **/
export class RawTraceEvents {
  constructor(private events: Object[]) {
  }

  getEvents(): Object[] {
    return this.events;
  }
}
