/*
 *  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.
 */

#ifndef MODULES_CONGESTION_CONTROLLER_SCREAM_TEST_CC_FEEDBACK_GENERATOR_H_
#define MODULES_CONGESTION_CONTROLLER_SCREAM_TEST_CC_FEEDBACK_GENERATOR_H_

#include <cstdint>
#include <deque>
#include <map>
#include <memory>
#include <optional>

#include "absl/functional/any_invocable.h"
#include "api/test/network_emulation/leaky_bucket_network_queue.h"
#include "api/test/network_emulation/network_queue.h"
#include "api/test/simulated_network.h"
#include "api/transport/network_types.h"
#include "api/units/data_rate.h"
#include "api/units/data_size.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "system_wrappers/include/clock.h"
#include "test/network/simulated_network.h"

namespace webrtc {

// Simulates sending packets with a given send rate over a simulated network and
// generates TransportPacketsFeedback that is supposed to match
// TransportPacketsFeedback from rtcp::CongestionControlFeedback (RFC8888).
class CcFeedbackGenerator {
 public:
  struct Config {
    SimulatedNetwork::Config network_config;
    TimeDelta time_between_feedback = TimeDelta::Millis(25);
    bool send_as_ect1 = true;
    std::unique_ptr<NetworkQueue> queue =
        std::make_unique<LeakyBucketNetworkQueue>(
            LeakyBucketNetworkQueue::Config{
                .max_ect1_sojourn_time = TimeDelta::Millis(8),
                .target_ect1_sojourn_time = TimeDelta::Millis(4)});
    DataSize packet_size = DataSize::Bytes(1000);
  };

  explicit CcFeedbackGenerator(Config config);

  // Processes the simulation until the next feedback message is received.
  // The function will send packets at the given send rate until the next
  // feedback message is generated.
  TransportPacketsFeedback ProcessUntilNextFeedback(DataRate send_rate,
                                                    SimulatedClock& clock) {
    return ProcessUntilNextFeedback(send_rate, clock, nullptr);
  }

  TransportPacketsFeedback ProcessUntilNextFeedback(
      DataRate send_rate,
      SimulatedClock& clock,
      absl::AnyInvocable<void(const SentPacket&)> sent_packet_cb,
      TimeDelta max_time = TimeDelta::Seconds(1));

  static int CountCeMarks(const TransportPacketsFeedback& feedback);

 private:
  std::optional<SentPacket> MaybeSendPackets(Timestamp time,
                                             DataRate send_rate);
  void ProcessNetwork(Timestamp time);
  std::optional<TransportPacketsFeedback> MaybeSendFeedback(Timestamp time);

  const DataSize packet_size_;
  const TimeDelta time_between_feedback_;
  const TimeDelta one_way_delay_;
  const bool send_as_ect1_;
  SimulatedNetwork network_;

  int64_t next_packet_id_ = 0;
  std::optional<int64_t> last_acked_sequence_number_;
  std::map<int64_t, PacketResult> sent_packets_;
  // `packets_received_` are packed that have been received by the remote, but
  // feedback has not yet been received by the sender. Feedback is delivered one
  // way delay later than when the packets were received.
  std::deque<PacketDeliveryInfo> packets_received_;

  Timestamp last_feedback_time_ = Timestamp::MinusInfinity();

  Timestamp last_send_budget_update = Timestamp::MinusInfinity();
  DataSize send_budget_;
};
}  // namespace webrtc

#endif  // MODULES_CONGESTION_CONTROLLER_SCREAM_TEST_CC_FEEDBACK_GENERATOR_H_
