// Copyright (c) 2025 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 "rtc_base/experiments/encoder_speed_experiment.h"

#include <string>

#include "api/field_trials.h"
#include "api/video/video_codec_type.h"
#include "api/video_codecs/video_codec.h"
#include "test/create_test_field_trials.h"
#include "test/gtest.h"

namespace webrtc {
namespace {

TEST(EncoderSpeedExperimentTest, EnabledByDefault) {
  FieldTrials field_trials = CreateTestFieldTrials("");
  EncoderSpeedExperiment config(field_trials);
  EXPECT_TRUE(config.IsDynamicSpeedEnabled());
}

TEST(EncoderSpeedExperimentTest, DynamicSpeedEnabled) {
  FieldTrials field_trials =
      CreateTestFieldTrials("WebRTC-EncoderSpeed/dynamic_speed:true/");
  EncoderSpeedExperiment config(field_trials);
  EXPECT_TRUE(config.IsDynamicSpeedEnabled());
}

TEST(EncoderSpeedExperimentTest, DynamicSpeedExplicitlyDisabled) {
  FieldTrials field_trials =
      CreateTestFieldTrials("WebRTC-EncoderSpeed/dynamic_speed:false/");
  EncoderSpeedExperiment config(field_trials);
  EXPECT_FALSE(config.IsDynamicSpeedEnabled());
}

TEST(EncoderSpeedExperimentTest, DefaultComplexity) {
  FieldTrials field_trials = CreateTestFieldTrials("");
  EncoderSpeedExperiment config(field_trials);

  // New defaults for AV1.
  EXPECT_EQ(config.GetComplexity(kVideoCodecAV1, /*is_screenshare=*/false),
            VideoCodecComplexity::kComplexityHigh);
  EXPECT_EQ(config.GetComplexity(kVideoCodecAV1, /*is_screenshare=*/true),
            VideoCodecComplexity::kComplexityLow);

  // All others default to normal for now, pending future experimentation.
  for (VideoCodecType codec :
       {kVideoCodecVP8, kVideoCodecVP9, kVideoCodecH264, kVideoCodecH265}) {
    EXPECT_EQ(config.GetComplexity(codec, /*is_screenshare=*/false),
              VideoCodecComplexity::kComplexityNormal);
    EXPECT_EQ(config.GetComplexity(codec, /*is_screenshare=*/true),
              VideoCodecComplexity::kComplexityNormal);
  }
}

TEST(EncoderSpeedExperimentTest, PerCodecComplexity) {
  FieldTrials field_trials = CreateTestFieldTrials(
      "WebRTC-EncoderSpeed/"
      "dynamic_speed:true,av1_camera:high,av1_screenshare:low,vp8_camera:max/");

  EncoderSpeedExperiment config(field_trials);
  EXPECT_TRUE(config.IsDynamicSpeedEnabled());

  // AV1
  EXPECT_EQ(config.GetComplexity(kVideoCodecAV1, /*is_screenshare=*/false),
            VideoCodecComplexity::kComplexityHigh);
  EXPECT_EQ(config.GetComplexity(kVideoCodecAV1, /*is_screenshare=*/true),
            VideoCodecComplexity::kComplexityLow);

  // VP8
  EXPECT_EQ(config.GetComplexity(kVideoCodecVP8, /*is_screenshare=*/false),
            VideoCodecComplexity::kComplexityMax);
  EXPECT_EQ(config.GetComplexity(kVideoCodecVP8, /*is_screenshare=*/true),
            VideoCodecComplexity::kComplexityNormal);  // Default

  // VP9 (Not specified)
  EXPECT_EQ(config.GetComplexity(kVideoCodecVP9, /*is_screenshare=*/false),
            VideoCodecComplexity::kComplexityNormal);
  EXPECT_EQ(config.GetComplexity(kVideoCodecVP9, /*is_screenshare=*/true),
            VideoCodecComplexity::kComplexityNormal);
}

TEST(EncoderSpeedExperimentTest, PerCodecComplexityDynamicSpeedDisabled) {
  FieldTrials field_trials = CreateTestFieldTrials(
      "WebRTC-EncoderSpeed/"
      "dynamic_speed:false,av1_camera:high,av1_screenshare:low/");

  EncoderSpeedExperiment config(field_trials);
  EXPECT_FALSE(config.IsDynamicSpeedEnabled());

  // AV1
  EXPECT_EQ(config.GetComplexity(kVideoCodecAV1, /*is_screenshare=*/false),
            VideoCodecComplexity::kComplexityHigh);
  EXPECT_EQ(config.GetComplexity(kVideoCodecAV1, /*is_screenshare=*/true),
            VideoCodecComplexity::kComplexityLow);
}

TEST(EncoderSpeedExperimentTest, InvalidCodecComplexityValue) {
  FieldTrials field_trials = CreateTestFieldTrials(
      "WebRTC-EncoderSpeed/"
      "dynamic_speed:true,vp8_camera:invalid,vp8_screenshare:max/");

  EncoderSpeedExperiment config(field_trials);
  EXPECT_TRUE(config.IsDynamicSpeedEnabled());
  EXPECT_EQ(config.GetComplexity(kVideoCodecVP8, /*is_screenshare=*/false),
            VideoCodecComplexity::kComplexityNormal);  // Invalid value
  EXPECT_EQ(config.GetComplexity(kVideoCodecVP8, /*is_screenshare=*/true),
            VideoCodecComplexity::kComplexityMax);
}

TEST(EncoderSpeedExperimentTest, InvalidDynamicSpeedValue) {
  FieldTrials field_trials =
      CreateTestFieldTrials("WebRTC-EncoderSpeed/dynamic_speed:invalid/");
  EncoderSpeedExperiment config(field_trials);
  EXPECT_TRUE(config.IsDynamicSpeedEnabled());  // Should default to true
}

TEST(EncoderSpeedExperimentTest, Vp9LowComplexityFallbackEnabled) {
  for (std::string trial : {"WebRTC-EncoderSpeed/dynamic_speed:true/",
                            "WebRTC-EncoderSpeed/dynamic_speed:false/"}) {
    FieldTrials field_trials = CreateTestFieldTrials(trial);
    EncoderSpeedExperiment config(field_trials,
                                  /*use_low_complexity_for_vp9=*/true);

    // VP9 should fallback to low complexity.
    EXPECT_EQ(config.GetComplexity(kVideoCodecVP9, /*is_screenshare=*/false),
              VideoCodecComplexity::kComplexityLow);
    EXPECT_EQ(config.GetComplexity(kVideoCodecVP9, /*is_screenshare=*/true),
              VideoCodecComplexity::kComplexityLow);

    // Other codecs should still be normal complexity.
    EXPECT_EQ(config.GetComplexity(kVideoCodecVP8, /*is_screenshare=*/false),
              VideoCodecComplexity::kComplexityNormal);
    EXPECT_EQ(config.GetComplexity(kVideoCodecH264, /*is_screenshare=*/false),
              VideoCodecComplexity::kComplexityNormal);
  }
}

TEST(EncoderSpeedExperimentTest,
     FieldTrialsTakePrecedenceOverVP9LowComplexityFlag) {
  for (std::string trial :
       {"WebRTC-EncoderSpeed/"
        "dynamic_speed:false,vp9_camera:high,vp9_screenshare:max/",
        "WebRTC-EncoderSpeed/"
        "dynamic_speed:true,vp9_camera:high,vp9_screenshare:max/"}) {
    FieldTrials field_trials = CreateTestFieldTrials(trial);
    EncoderSpeedExperiment config(field_trials,
                                  /*use_low_complexity_for_vp9=*/true);

    // VP9 should use the configured complexity instead of falling back.
    EXPECT_EQ(config.GetComplexity(kVideoCodecVP9, /*is_screenshare=*/false),
              VideoCodecComplexity::kComplexityHigh);
    EXPECT_EQ(config.GetComplexity(kVideoCodecVP9, /*is_screenshare=*/true),
              VideoCodecComplexity::kComplexityMax);
  }
}

TEST(EncoderSpeedExperimentTest, Vp9LowComplexityFallbackDisabled) {
  FieldTrials field_trials =
      CreateTestFieldTrials("WebRTC-EncoderSpeed/dynamic_speed:true/");
  EncoderSpeedExperiment config(field_trials,
                                /*use_low_complexity_for_vp9=*/false);

  // VP9 should be normal complexity.
  EXPECT_EQ(config.GetComplexity(kVideoCodecVP9, /*is_screenshare=*/false),
            VideoCodecComplexity::kComplexityNormal);
  EXPECT_EQ(config.GetComplexity(kVideoCodecVP9, /*is_screenshare=*/true),
            VideoCodecComplexity::kComplexityNormal);
}

}  // namespace

}  // namespace webrtc
