/*
 *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "test/pc/e2e/cross_media_metrics_reporter.h"

#include <utility>
#include <vector>

#include "api/stats/rtc_stats.h"
#include "api/stats/rtcstats_objects.h"
#include "api/test/metrics/metric.h"
#include "api/units/timestamp.h"
#include "rtc_base/checks.h"
#include "rtc_base/event.h"
#include "system_wrappers/include/field_trial.h"
#include "test/pc/e2e/metric_metadata_keys.h"

namespace webrtc {
namespace webrtc_pc_e2e {

using ::webrtc::test::ImprovementDirection;
using ::webrtc::test::Unit;

CrossMediaMetricsReporter::CrossMediaMetricsReporter(
    test::MetricsLogger* metrics_logger)
    : metrics_logger_(metrics_logger) {
  RTC_CHECK(metrics_logger_);
}

void CrossMediaMetricsReporter::Start(
    absl::string_view test_case_name,
    const TrackIdStreamInfoMap* reporter_helper) {
  test_case_name_ = std::string(test_case_name);
  reporter_helper_ = reporter_helper;
}

void CrossMediaMetricsReporter::OnStatsReports(
    absl::string_view pc_label,
    const rtc::scoped_refptr<const RTCStatsReport>& report) {
  auto inbound_stats = report->GetStatsOfType<RTCInboundRTPStreamStats>();
  std::map<std::string, std::vector<const RTCInboundRTPStreamStats*>>
      sync_group_stats;
  for (const auto& stat : inbound_stats) {
    auto media_source_stat =
        report->GetAs<DEPRECATED_RTCMediaStreamTrackStats>(*stat->track_id);
    if (stat->estimated_playout_timestamp.ValueOrDefault(0.) > 0 &&
        media_source_stat->track_identifier.is_defined()) {
      sync_group_stats[reporter_helper_
                           ->GetStreamInfoFromTrackId(
                               *media_source_stat->track_identifier)
                           .sync_group]
          .push_back(stat);
    }
  }

  MutexLock lock(&mutex_);
  for (const auto& pair : sync_group_stats) {
    // If there is less than two streams, it is not a sync group.
    if (pair.second.size() < 2) {
      continue;
    }
    auto sync_group = std::string(pair.first);
    const RTCInboundRTPStreamStats* audio_stat = pair.second[0];
    const RTCInboundRTPStreamStats* video_stat = pair.second[1];

    RTC_CHECK(pair.second.size() == 2 && audio_stat->kind.is_defined() &&
              video_stat->kind.is_defined() &&
              *audio_stat->kind != *video_stat->kind)
        << "Sync group should consist of one audio and one video stream.";

    if (*audio_stat->kind == RTCMediaStreamTrackKind::kVideo) {
      std::swap(audio_stat, video_stat);
    }
    // Stream labels of a sync group are same for all polls, so we need it add
    // it only once.
    if (stats_info_.find(sync_group) == stats_info_.end()) {
      auto audio_source_stat =
          report->GetAs<DEPRECATED_RTCMediaStreamTrackStats>(
              *audio_stat->track_id);
      auto video_source_stat =
          report->GetAs<DEPRECATED_RTCMediaStreamTrackStats>(
              *video_stat->track_id);
      // *_source_stat->track_identifier is always defined here because we
      // checked it while grouping stats.
      stats_info_[sync_group].audio_stream_info =
          reporter_helper_->GetStreamInfoFromTrackId(
              *audio_source_stat->track_identifier);
      stats_info_[sync_group].video_stream_info =
          reporter_helper_->GetStreamInfoFromTrackId(
              *video_source_stat->track_identifier);
    }

    double audio_video_playout_diff = *audio_stat->estimated_playout_timestamp -
                                      *video_stat->estimated_playout_timestamp;
    if (audio_video_playout_diff > 0) {
      stats_info_[sync_group].audio_ahead_ms.AddSample(
          audio_video_playout_diff);
      stats_info_[sync_group].video_ahead_ms.AddSample(0);
    } else {
      stats_info_[sync_group].audio_ahead_ms.AddSample(0);
      stats_info_[sync_group].video_ahead_ms.AddSample(
          std::abs(audio_video_playout_diff));
    }
  }
}

void CrossMediaMetricsReporter::StopAndReportResults() {
  MutexLock lock(&mutex_);
  for (const auto& pair : stats_info_) {
    const std::string& sync_group = pair.first;
    std::map<std::string, std::string> audio_metric_metadata{
        {MetricMetadataKey::kPeerSyncGroupMetadataKey, sync_group},
        {MetricMetadataKey::kAudioStreamMetadataKey,
         pair.second.audio_stream_info.stream_label},
        {MetricMetadataKey::kPeerMetadataKey,
         pair.second.audio_stream_info.receiver_peer},
        {MetricMetadataKey::kReceiverMetadataKey,
         pair.second.audio_stream_info.receiver_peer}};
    metrics_logger_->LogMetric(
        "audio_ahead_ms",
        GetTestCaseName(pair.second.audio_stream_info.stream_label, sync_group),
        pair.second.audio_ahead_ms, Unit::kMilliseconds,
        webrtc::test::ImprovementDirection::kSmallerIsBetter,
        std::move(audio_metric_metadata));

    std::map<std::string, std::string> video_metric_metadata{
        {MetricMetadataKey::kPeerSyncGroupMetadataKey, sync_group},
        {MetricMetadataKey::kAudioStreamMetadataKey,
         pair.second.video_stream_info.stream_label},
        {MetricMetadataKey::kPeerMetadataKey,
         pair.second.video_stream_info.receiver_peer},
        {MetricMetadataKey::kReceiverMetadataKey,
         pair.second.video_stream_info.receiver_peer}};
    metrics_logger_->LogMetric(
        "video_ahead_ms",
        GetTestCaseName(pair.second.video_stream_info.stream_label, sync_group),
        pair.second.video_ahead_ms, Unit::kMilliseconds,
        webrtc::test::ImprovementDirection::kSmallerIsBetter,
        std::move(video_metric_metadata));
  }
}

std::string CrossMediaMetricsReporter::GetTestCaseName(
    const std::string& stream_label,
    const std::string& sync_group) const {
  return test_case_name_ + "/" + sync_group + "_" + stream_label;
}

}  // namespace webrtc_pc_e2e
}  // namespace webrtc
