#include "w3cs_video_rate.h"

#include <cstdio>
#include <cstdlib>

#define CHECK(condition)                                                    \
  do {                                                                      \
    if (!(condition)) {                                                     \
      std::fprintf(stderr, "%s:%d: check failed: %s\n", __FILE__, __LINE__, \
                   #condition);                                             \
      std::exit(1);                                                         \
    }                                                                       \
  } while (0)

int main() {
  // Start inside the range; a start outside it is clamped.
  w3cs::VideoRateController rate(3000, 1200, 6000);
  CHECK(rate.kbps == 3000);
  CHECK(w3cs::VideoRateController(9000, 1200, 6000).kbps == 6000);
  CHECK(w3cs::VideoRateController(100, 1200, 6000).kbps == 1200);

  // Too few packets (a parked interval) never changes anything.
  CHECK(!rate.observe(5, 5, 0.05));
  CHECK(rate.kbps == 3000);

  // Heavy loss cuts by 30% immediately, bounded below by the floor.
  CHECK(rate.observe(10, 190, 0.05));
  CHECK(rate.kbps == 2100);
  for (int index = 0; index < 10; ++index) rate.observe(50, 100, 0.05);
  CHECK(rate.kbps == 1200);

  // Light loss holds: no cut, and the clean run restarts.
  w3cs::VideoRateController hold(3000, 1200, 6000);
  for (int index = 0; index < 5; ++index) CHECK(!hold.observe(0, 200, 0.05));
  CHECK(!hold.observe(3, 197, 0.05));   // 1.5% loss
  CHECK(hold.kbps == 3000 && hold.clean_samples == 0);

  // Six clean seconds climb 15%, capped at the ceiling.
  w3cs::VideoRateController climb(3000, 1200, 6000);
  for (int index = 0; index < 5; ++index) CHECK(!climb.observe(0, 200, 0.05));
  CHECK(climb.observe(0, 200, 0.05));
  CHECK(climb.kbps == 3450);
  for (int index = 0; index < 60; ++index) climb.observe(0, 200, 0.05);
  CHECK(climb.kbps == 6000);

  // A bloated path reads like loss: heavy RTT cuts, light RTT holds.
  w3cs::VideoRateController bloat(3000, 1200, 6000);
  CHECK(!bloat.observe(0, 200, 0.5));
  CHECK(bloat.clean_samples == 0);
  CHECK(bloat.observe(0, 200, 0.9));
  CHECK(bloat.kbps == 2100);

  std::puts("w3cs-video-rate-test ok");
  return 0;
}
