// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <lib/syslog/cpp/macros.h>

#include <audio-proto-utils/format-utils.h>
#include <gtest/gtest.h>

#include "src/media/audio/audio_core/testing/fake_audio_driver.h"

namespace media::audio::testing {

FakeAudioDriverV2::FakeAudioDriverV2(zx::channel channel, async_dispatcher_t* dispatcher)
    : dispatcher_(dispatcher), stream_binding_(this, std::move(channel), dispatcher) {
  formats_.number_of_channels.push_back(2);
  formats_.sample_formats.push_back(fuchsia::hardware::audio::SampleFormat::PCM_SIGNED);
  formats_.bytes_per_sample.push_back(2);
  formats_.valid_bits_per_sample.push_back(16);
  formats_.frame_rates.push_back(48000);
  Stop();
}

void FakeAudioDriverV2::Start() {
  assert(!stream_binding_.is_bound());
  stream_binding_.Bind(std::move(stream_req_), dispatcher_);
  if (ring_buffer_binding_.has_value() && !ring_buffer_binding_->is_bound()) {
    ring_buffer_binding_->Bind(std::move(ring_buffer_req_), dispatcher_);
  }
}

void FakeAudioDriverV2::Stop() {
  if (stream_binding_.is_bound()) {
    stream_req_ = stream_binding_.Unbind();
  }
  if (ring_buffer_binding_.has_value() && ring_buffer_binding_->is_bound()) {
    ring_buffer_req_ = ring_buffer_binding_->Unbind();
  }
}

fzl::VmoMapper FakeAudioDriverV2::CreateRingBuffer(size_t size) {
  FX_CHECK(!ring_buffer_) << "Calling CreateRingBuffer multiple times is not supported";

  ring_buffer_size_ = size;
  fzl::VmoMapper mapper;
  mapper.CreateAndMap(ring_buffer_size_, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, nullptr,
                      &ring_buffer_);
  return mapper;
}

void FakeAudioDriverV2::GetProperties(
    fuchsia::hardware::audio::StreamConfig::GetPropertiesCallback callback) {
  fuchsia::hardware::audio::StreamProperties props = {};

  std::memcpy(props.mutable_unique_id()->data(), uid_.data, sizeof(uid_.data));
  props.set_manufacturer(manufacturer_);
  props.set_product(product_);
  props.set_can_mute(can_mute_);
  props.set_can_agc(can_agc_);
  props.set_min_gain_db(gain_limits_.first);
  props.set_max_gain_db(gain_limits_.second);
  props.set_gain_step_db(0.001f);
  props.set_plug_detect_capabilities(
      fuchsia::hardware::audio::PlugDetectCapabilities::CAN_ASYNC_NOTIFY);
  props.set_clock_domain(clock_domain_);

  callback(std::move(props));
}

void FakeAudioDriverV2::GetSupportedFormats(
    fuchsia::hardware::audio::StreamConfig::GetSupportedFormatsCallback callback) {
  fuchsia::hardware::audio::SupportedFormats formats = {};
  formats.set_pcm_supported_formats(formats_);

  std::vector<fuchsia::hardware::audio::SupportedFormats> all_formats = {};
  all_formats.push_back(std::move(formats));
  callback(std::move(all_formats));
}

void FakeAudioDriverV2::CreateRingBuffer(
    fuchsia::hardware::audio::Format format,
    ::fidl::InterfaceRequest<fuchsia::hardware::audio::RingBuffer> ring_buffer) {
  ring_buffer_binding_.emplace(this, ring_buffer.TakeChannel(), dispatcher_);
  selected_format_ = format.pcm_format();
}

void FakeAudioDriverV2::WatchGainState(
    fuchsia::hardware::audio::StreamConfig::WatchGainStateCallback callback) {
  if (gain_state_sent_) {
    return;  // Only send gain state once, as if it never changed.
  }
  gain_state_sent_ = true;
  fuchsia::hardware::audio::GainState gain_state = {};
  gain_state.set_muted(cur_mute_);
  gain_state.set_agc_enabled(cur_agc_);
  gain_state.set_gain_db(cur_gain_);
  callback(std::move(gain_state));
}

void FakeAudioDriverV2::SetGain(fuchsia::hardware::audio::GainState target_state) {}

void FakeAudioDriverV2::WatchPlugState(
    fuchsia::hardware::audio::StreamConfig::WatchPlugStateCallback callback) {
  if (plug_state_sent_) {
    return;  // Only send plug state once, as if it never changed.
  }
  plug_state_sent_ = true;
  fuchsia::hardware::audio::PlugState plug_state = {};
  plug_state.set_plugged(true);
  plug_state.set_plug_state_time(0);
  callback(std::move(plug_state));
}

void FakeAudioDriverV2::GetProperties(
    fuchsia::hardware::audio::RingBuffer::GetPropertiesCallback callback) {
  fuchsia::hardware::audio::RingBufferProperties props = {};

  props.set_external_delay(external_delay_.get());
  props.set_fifo_depth(fifo_depth_);
  props.set_needs_cache_flush_or_invalidate(false);

  callback(std::move(props));
}

void FakeAudioDriverV2::SendPositionNotification(zx::time timestamp, uint32_t position) {
  position_notify_timestamp_mono_ = timestamp;
  position_notify_position_bytes_ = position;

  position_notification_values_are_set_ = true;
  if (position_notify_callback_) {
    PositionNotification();
  }
}

void FakeAudioDriverV2::WatchClockRecoveryPositionInfo(
    fuchsia::hardware::audio::RingBuffer::WatchClockRecoveryPositionInfoCallback callback) {
  position_notify_callback_ = std::move(callback);

  if (position_notification_values_are_set_) {
    PositionNotification();
  }
}

void FakeAudioDriverV2::PositionNotification() {
  FX_CHECK(position_notify_callback_);
  FX_CHECK(position_notification_values_are_set_);

  // Real audio drivers can't emit position notifications until started; we shouldn't either
  if (is_running_) {
    // Clear both prerequisites for sending this notification
    position_notification_values_are_set_ = false;
    auto callback = *std::move(position_notify_callback_);
    position_notify_callback_ = std::nullopt;

    fuchsia::hardware::audio::RingBufferPositionInfo info{
        .timestamp = position_notify_timestamp_mono_.get(),
        .position = position_notify_position_bytes_,
    };

    callback(std::move(info));
  }
}

void FakeAudioDriverV2::GetVmo(uint32_t min_frames, uint32_t clock_recovery_notifications_per_ring,
                               fuchsia::hardware::audio::RingBuffer::GetVmoCallback callback) {
  // This should be true since it's set as part of creating the channel that's carrying these
  // messages.
  FX_CHECK(selected_format_);

  if (!ring_buffer_) {
    // If we haven't created a ring buffer, we'll just drop this request.
    return;
  }
  FX_CHECK(ring_buffer_);

  // Dup our ring buffer VMO to send over the channel.
  zx::vmo dup;
  FX_CHECK(ring_buffer_.duplicate(ZX_RIGHT_SAME_RIGHTS, &dup) == ZX_OK);

  // Compute the buffer size in frames.
  auto frame_size = selected_format_->number_of_channels * selected_format_->bytes_per_sample;
  auto ring_buffer_frames = ring_buffer_size_ / frame_size;

  fuchsia::hardware::audio::RingBuffer_GetVmo_Result result = {};
  fuchsia::hardware::audio::RingBuffer_GetVmo_Response response = {};
  response.num_frames = ring_buffer_frames;
  response.ring_buffer = std::move(dup);
  result.set_response(std::move(response));
  callback(std::move(result));
}

void FakeAudioDriverV2::Start(fuchsia::hardware::audio::RingBuffer::StartCallback callback) {
  EXPECT_TRUE(!is_running_);
  mono_start_time_ = async::Now(dispatcher_);
  is_running_ = true;

  callback(mono_start_time_.get());
}

void FakeAudioDriverV2::Stop(fuchsia::hardware::audio::RingBuffer::StopCallback callback) {
  EXPECT_TRUE(is_running_);
  is_running_ = false;

  position_notify_callback_ = std::nullopt;
  position_notification_values_are_set_ = false;

  callback();
}

}  // namespace media::audio::testing
