/*
 *  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 VIDEO_TIMING_SIMULATOR_RTC_EVENT_LOG_DRIVER_H_
#define VIDEO_TIMING_SIMULATOR_RTC_EVENT_LOG_DRIVER_H_

#include <cstdint>
#include <memory>
#include <optional>
#include <set>

#include "absl/base/nullability.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/functional/any_invocable.h"
#include "absl/strings/string_view.h"
#include "api/environment/environment.h"
#include "api/task_queue/task_queue_base.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "logging/rtc_event_log/events/logged_rtp_rtcp.h"
#include "logging/rtc_event_log/events/rtc_event_video_receive_stream_config.h"
#include "logging/rtc_event_log/rtc_event_log_parser.h"
#include "logging/rtc_event_log/rtc_event_processor.h"
#include "rtc_base/thread_annotations.h"
#include "test/time_controller/simulated_time_task_queue_controller.h"
#include "video/timing/simulator/rtp_packet_simulator.h"

namespace webrtc::video_timing_simulator {

// The `RtcEventLogDriver` is responsible for driving a simulation given an
// RtcEventLog. It walks through the relevant events in the log in
// `log_timestamp` order, and provides the events to an underlying `stream`
// abstraction. This abstraction allows the `RtcEventLogDriver` to be agnostic
// w.r.t. how the simulated packets are used. We will provide abstractions for
// decodability tracking and simulated rendering, but in the future we could
// also wrap all of `VideoReceiveStream2`, to have a "full stack simulation".
//
// The `RtcEventLogDriver` is responsible for the environment and the
// simulated time task queues. All worker objects should be single-threaded,
// running on the provided task queue(s).
//
// TODO: b/423646186 - Improvements:
//  * Handle `LogSegment`s.
//  * Handle stop events.
//  * Parse RTT updates from RTCPs.
class RtcEventLogDriver {
 public:
  // Configuration for the `RtcEventLogDriver` itself.
  struct Config {
    // If true, existing streams are reused, even if a new
    // `LoggedVideoRecvConfig` was logged for the same stream. (This might
    // happen around `SetRemoteDescription`s.)
    bool reuse_streams = false;

    // If non-empty, will only simulate video streams whose main SSRCs is
    // contained in the set.
    std::set<uint32_t> ssrc_filter = {};
  };

  // A stream that is driven by simulated RTP packets coming from the log.
  class StreamInterface {
   public:
    virtual ~StreamInterface() = default;
    // Insert `simulated_packet` into the stream.
    virtual void InsertSimulatedPacket(
        const RtpPacketSimulator::SimulatedPacket& simulated_packet) = 0;
    // Notify the stream that no more packets will be inserted.
    virtual void Close() = 0;
  };

  // Factory that creates a stream given the environment and the stream SSRCs.
  using StreamInterfaceFactory =
      absl::AnyInvocable<std::unique_ptr<StreamInterface>(const Environment&,
                                                          /*ssrc=*/uint32_t,
                                                          /*rtx_ssrc=*/uint32_t)
                             const>;

  // Slack added after final event, in order to catch any straggling frames.
  static constexpr TimeDelta kShutdownAdvanceTimeSlack = TimeDelta::Millis(100);

  RtcEventLogDriver(const Config& config,
                    const ParsedRtcEventLog* absl_nonnull parsed_log,
                    absl::string_view field_trials_string,
                    StreamInterfaceFactory stream_factory);
  ~RtcEventLogDriver();

  RtcEventLogDriver(const RtcEventLogDriver&) = delete;
  RtcEventLogDriver& operator=(const RtcEventLogDriver&) = delete;

  // Perform the simulation. Should only be called once per instantiation.
  void Simulate();

  Timestamp GetCurrentTimeForTesting() {
    return time_controller_.GetClock()->CurrentTime();
  }

 private:
  // Simulation.
  // Sets the `time_controller_` simulated time to `log_timestamp`, thus
  // executing all relevant tasks on the `simulator_queue_`.
  void AdvanceTime(Timestamp log_timestamp);

  // Advances time according to `log_timestamp`, and handles the event through
  // the `handler`.
  void HandleEvent(Timestamp log_timestamp,
                   absl::AnyInvocable<void() &&> handler);

  // RtcEventProcessor callbacks (running on main thread).
  void OnLoggedVideoRecvConfig(const LoggedVideoRecvConfig& config);
  void OnLoggedRtpPacketIncoming(const LoggedRtpPacketIncoming& packet);

  // Environment.
  const Config config_;
  SimulatedTimeTaskQueueController time_controller_;
  const Environment env_;

  // Input.
  const ParsedRtcEventLog& parsed_log_;
  StreamInterfaceFactory stream_factory_;

  // Simulator.
  RtcEventProcessor processor_;
  std::optional<Timestamp> prev_log_timestamp_;
  std::unique_ptr<TaskQueueBase, TaskQueueDeleter> simulator_queue_;
  RtpPacketSimulator packet_simulator_ RTC_GUARDED_BY(simulator_queue_);
  // Owned streams. Keyed by `ssrc`, so that they can be replaced if needed.
  absl::flat_hash_map<uint32_t, std::unique_ptr<StreamInterface>> streams_
      RTC_GUARDED_BY(simulator_queue_);
  // Streams for reception. Keyed by both `ssrc` and `rtx_ssrc`.
  absl::flat_hash_map<uint32_t, StreamInterface*> receiving_streams_
      RTC_GUARDED_BY(simulator_queue_);
  // Keep track of all logged `ssrc`s for text logging purposes.
  absl::flat_hash_set<uint32_t> all_known_ssrcs_
      RTC_GUARDED_BY(simulator_queue_);
};

}  // namespace webrtc::video_timing_simulator

#endif  // VIDEO_TIMING_SIMULATOR_RTC_EVENT_LOG_DRIVER_H_
