function log(...args) {
  console.log.apply(null, ["[webrtc-internal-exporter:override]", ...args]);
}

log("Override RTCPeerConnection.");

class WebrtcInternalExporter {
  peerConnections = new Map();

  url = "";
  enabled = false;
  updateInterval = 2000;
  enabledStats = [];

  constructor() {
    window.addEventListener("message", async (message) => {
      const { event, options } = message.data;
      if (event === "webrtc-internal-exporter:options") {
        log("options updated:", options);
        Object.assign(this, options);
      }
    });

    window.postMessage({ event: "webrtc-internal-exporter:ready" });
    this.collectAllStats();
  }

  randomId() {
    return (
      window.crypto?.randomUUID() || (2 ** 64 * Math.random()).toString(16)
    );
  }

  add(pc) {
    const id = this.randomId();
    this.peerConnections.set(id, pc);
    pc.addEventListener("connectionstatechange", () => {
      if (pc.connectionState === "closed") {
        this.peerConnections.delete(id);
      }
    });
    //this.collectAndPostStats(id);
  }

  async collectAndPostSingleStat(id) {
    const stats = await this.collectStats(id, this.collectAndPostSingleStat);
    if (Object.keys(stats).length === 0 || !stats) return;

    window.postMessage(
      {
        event: "webrtc-internal-exporter:peer-connection-stats",
        ...stats,
      },
      [stats],
    );
  }

  async collectAllStats() {
    const stats = [];

    for (const [id, pc] of this.peerConnections) {
      if (this.url && this.enabled && pc.connectionState === "connected") {
        const pcStats = await this.collectStats(id, pc);
        stats.push(pcStats);
      }
    }

      window.postMessage(
        {
          event: "webrtc-internal-exporter:peer-connections-stats",
          stats,
        },
        [stats],
      );

      log(`Stats collected:`, stats);

  setTimeout(this.collectAllStats.bind(this), this.updateInterval);
  return stats;
  }

  async collectStats(id, pc, binding) {
    var completeStats = {};

    if (!pc) {
      pc = this.peerConnections.get(id);
      if (!pc) return;
    }

    if (this.url && this.enabled && pc.connectionState === "connected") {
      try {
        const stats = await pc.getStats();
        const values = [...stats.values()].filter(
          (v) =>
            ["peer-connection", ...this.enabledStats].indexOf(v.type) !== -1
        );

        completeStats = {
          url: window.location.href,
          id,
          state: pc.connectionState,
          values,
        };
      } catch (error) {
        log(`collectStats error: ${error.message}`);
      }
    }

    if (pc.connectionState === "closed") {
      this.peerConnections.delete(id);
    } else {
      if (binding) {
        setTimeout(binding.bind(this), this.updateInterval, id);
      }
    }

    return completeStats;
  }
}

const webrtcInternalExporter = new WebrtcInternalExporter();

window.RTCPeerConnection = new Proxy(window.RTCPeerConnection, {
  construct(target, argumentsList) {
    log(`RTCPeerConnection`, argumentsList);

    const pc = new target(...argumentsList);

    webrtcInternalExporter.add(pc);

    return pc;
  },
});
