// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_MOJO_SERVICES_MEDIA_METRICS_PROVIDER_H_
#define MEDIA_MOJO_SERVICES_MEDIA_METRICS_PROVIDER_H_

#include <stdint.h>

#include <optional>
#include <string>

#include "base/time/time.h"
#include "base/types/id_type.h"
#include "media/base/container_names.h"
#include "media/base/demuxer.h"
#include "media/base/picture_in_picture_events_info.h"
#include "media/base/pipeline_status.h"
#include "media/base/renderer_factory_selector.h"
#include "media/base/timestamp_constants.h"
#include "media/mojo/mojom/media_metrics_provider.mojom.h"
#include "media/mojo/services/media_mojo_export.h"
#include "media/mojo/services/video_decode_perf_history.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "url/gurl.h"

namespace media {

// alias the name for readability
using MediaPlayerUkmId = base::IdTypeU64<class MediaPlayerUkmIDTag>;

MEDIA_MOJO_EXPORT MediaPlayerUkmId GetNextMediaPlayerUkmId();

class VideoDecodePerfHistory;

// See mojom::MediaMetricsProvider for documentation.
class MEDIA_MOJO_EXPORT MediaMetricsProvider
    : public mojom::MediaMetricsProvider {
 public:
  enum class BrowsingMode : bool { kIncognito, kNormal };

  enum class FrameStatus : bool { kTopFrame, kNotTopFrame };

  using IsShuttingDownCallback = base::RepeatingCallback<bool(void)>;

  MediaMetricsProvider(
      BrowsingMode is_incognito,
      FrameStatus is_top_frame,
      ukm::SourceId source_id,
      VideoDecodePerfHistory::SaveCallback save_cb,
      IsShuttingDownCallback is_shutting_down_cb,
      PictureInPictureEventsInfo::AutoPipReasonCallback auto_pip_reason_cb);

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

  ~MediaMetricsProvider() override;

  // Callback for retrieving a ukm::SourceId.
  using GetSourceIdCallback = base::RepeatingCallback<ukm::SourceId(void)>;

  using GetLastCommittedURLCallback =
      base::RepeatingCallback<const GURL&(void)>;

  // Creates a MediaMetricsProvider, |perf_history| may be nullptr if perf
  // history database recording is disabled.
  static void Create(
      BrowsingMode is_incognito,
      FrameStatus is_top_frame,
      ukm::SourceId source_id,
      VideoDecodePerfHistory::SaveCallback save_cb,
      IsShuttingDownCallback is_shutting_down_cb,
      PictureInPictureEventsInfo::AutoPipReasonCallback auto_pip_reason_cb,
      mojo::PendingReceiver<mojom::MediaMetricsProvider> receiver);

 private:
  struct PipelineInfo {
    explicit PipelineInfo(bool is_incognito);
    ~PipelineInfo();
    bool is_incognito;
    bool has_ever_played = false;
    bool has_reached_have_enough = false;
    bool has_audio = false;
    bool has_video = false;
    bool is_eme = false;
    bool video_decoder_changed = false;
    bool has_track_change_ = false;
    AudioCodec audio_codec = AudioCodec::kUnknown;
    VideoCodec video_codec = VideoCodec::kUnknown;
    VideoPipelineInfo video_pipeline_info;
    AudioPipelineInfo audio_pipeline_info;
    std::optional<PipelineStatusCodes> start_status_;
    PipelineStatusCodes last_pipeline_status = PIPELINE_OK;
  };

  struct MediaInfo {
    const bool is_mse;
    const mojom::MediaURLScheme url_scheme;
    const mojom::MediaStreamType media_stream_type;
  };

  // mojom::MediaMetricsProvider implementation:
  void Initialize(bool is_mse,
                  mojom::MediaURLScheme url_scheme,
                  mojom::MediaStreamType media_stream_type) override;
  void OnStarted(const PipelineStatus& status) override;
  void OnError(const PipelineStatus& status) override;
  void OnFallback(const PipelineStatus& status) override;
  void SetAudioPipelineInfo(const AudioPipelineInfo& info) override;
  void SetContainerName(
      container_names::MediaContainerName container_name) override;
  void SetRendererType(RendererType renderer_type) override;
  void SetDemuxerType(DemuxerType renderer_type) override;
  void SetKeySystem(const std::string& key_system) override;
  void SetHasWaitingForKey() override;
  void SetIsHardwareSecure() override;
  void SetHasAudio(AudioCodec audio_codec) override;
  void SetHasPlayed() override;
  void SetHasVideo(VideoCodec video_codec) override;
  void SetHaveEnough() override;
  void SetIsEME() override;
  void SetHasTrackChange() override;
  void SetTimeToMetadata(base::TimeDelta elapsed) override;
  void SetTimeToFirstFrame(base::TimeDelta elapsed) override;
  void SetTimeToPlayReady(base::TimeDelta elapsed) override;
  void SetVisibilityRatioAtPlaybackStart(double ratio) override;
  void SetVideoPipelineInfo(const VideoPipelineInfo& info) override;

  void AcquireWatchTimeRecorder(
      mojom::PlaybackPropertiesPtr properties,
      mojo::PendingReceiver<mojom::WatchTimeRecorder> receiver) override;
  void AcquireVideoDecodeStatsRecorder(
      mojo::PendingReceiver<mojom::VideoDecodeStatsRecorder> receiver) override;
  void AcquirePlaybackEventsRecorder(
      mojo::PendingReceiver<mojom::PlaybackEventsRecorder> receiver) override;

  void ReportPipelineUMA();
  std::string GetUMANameForAVStream(const PipelineInfo& player_info);

  bool IsInitialized() const;

  // Session unique ID which maps to a given WebMediaPlayerImpl instances. Used
  // to coordinate multiply logged events with a singly logged metric.
  const MediaPlayerUkmId player_id_;

  // Are UKM reports for the main frame or for a subframe?
  const bool is_top_frame_;

  const ukm::SourceId source_id_;

  const VideoDecodePerfHistory::SaveCallback save_cb_;
  const IsShuttingDownCallback is_shutting_down_cb_;
  const PictureInPictureEventsInfo::AutoPipReasonCallback auto_pip_reason_cb_;

  // UMA pipeline packaged data
  PipelineInfo uma_info_;

  // The values below are only set if `Initialize` has been called.
  std::optional<MediaInfo> media_info_;

  RendererType renderer_type_ = RendererType::kRendererImpl;
  DemuxerType demuxer_type_ = DemuxerType::kUnknownDemuxer;
  std::string key_system_;
  bool has_waiting_for_key_ = false;
  bool is_hardware_secure_ = false;

  base::TimeDelta time_to_metadata_ = kNoTimestamp;
  base::TimeDelta time_to_first_frame_ = kNoTimestamp;
  base::TimeDelta time_to_play_ready_ = kNoTimestamp;

  std::optional<double> visibility_ratio_at_playback_start_;

  std::optional<container_names::MediaContainerName> container_name_;
};

}  // namespace media

#endif  // MEDIA_MOJO_SERVICES_MEDIA_METRICS_PROVIDER_H_
