// 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 "src/media/audio/audio_core/audio_tuner_impl.h"

#include <filesystem>

#include "src/media/audio/audio_core/audio_device.h"
#include "src/media/audio/audio_core/audio_device_manager.h"
#include "src/media/audio/audio_core/stream_usage.h"
#include "src/media/audio/lib/effects_loader/effects_loader.h"

namespace media::audio {

fidl::InterfaceRequestHandler<fuchsia::media::tuning::AudioTuner>
AudioTunerImpl::GetFidlRequestHandler() {
  return bindings_.GetHandler(this);
}

void AudioTunerImpl::GetAvailableAudioEffects(GetAvailableAudioEffectsCallback callback) {
  std::vector<fuchsia::media::tuning::AudioEffectType> available_effects;
  for (auto& file : std::filesystem::directory_iterator("/pkg/lib")) {
    if (file.is_directory()) {
      continue;
    }

    auto lib_name = file.path().filename();
    std::unique_ptr<EffectsLoader> loader;
    zx_status_t status = EffectsLoader::CreateWithModule(lib_name.c_str(), &loader);
    if (status != ZX_OK) {
      continue;
    }

    for (uint32_t id = 0; id < loader->GetNumEffects(); ++id) {
      fuchsia_audio_effects_description desc;
      zx_status_t status = loader->GetEffectInfo(id, &desc);
      if (status != ZX_OK) {
        continue;
      }

      fuchsia::media::tuning::AudioEffectType effect;
      effect.set_module_name(lib_name.string());
      effect.set_effect_name(desc.name);
      available_effects.push_back(std::move(effect));
    }
  }
  callback(std::move(available_effects));
}

void AudioTunerImpl::GetAudioDeviceProfile(std::string device_id,
                                           GetAudioDeviceProfileCallback callback) {
  auto tuned_specification_it = tuned_device_specifications_.find(device_id);
  auto device = tuned_specification_it != tuned_device_specifications_.end()
                    ? tuned_specification_it->second
                    : GetDefaultDeviceSpecification(device_id);
  callback(ToAudioDeviceTuningProfile(device.pipeline_config, device.volume_curve));
}

void AudioTunerImpl::GetDefaultAudioDeviceProfile(std::string device_id,
                                                  GetDefaultAudioDeviceProfileCallback callback) {
  auto default_device = GetDefaultDeviceSpecification(device_id);
  callback(ToAudioDeviceTuningProfile(default_device.pipeline_config, default_device.volume_curve));
}

void AudioTunerImpl::SetAudioDeviceProfile(std::string device_id,
                                           fuchsia::media::tuning::AudioDeviceTuningProfile profile,
                                           SetAudioDeviceProfileCallback callback) {
  auto config = PipelineConfig(ToPipelineConfigMixGroup(std::move(profile.pipeline())));
  auto volume_curve = ToVolumeCurve(profile.volume_curve());
  auto promise = context_.device_manager().UpdatePipelineConfig(device_id, config, volume_curve);

  context_.threading_model().FidlDomain().executor()->schedule_task(
      promise.then([this, device_id, config, volume_curve,
                    callback = std::move(callback)](fit::result<void, zx_status_t>& result) {
        if (result.is_ok()) {
          auto tuned_device_it = tuned_device_specifications_.find(device_id);
          if (tuned_device_it != tuned_device_specifications_.end()) {
            tuned_device_it->second =
                OutputDeviceSpecification{.pipeline_config = config, .volume_curve = volume_curve};
          } else {
            tuned_device_specifications_.emplace(
                device_id,
                OutputDeviceSpecification{.pipeline_config = config, .volume_curve = volume_curve});
          }
          callback(ZX_OK);
        } else {
          callback(result.take_error());
        }
      }));
}

void AudioTunerImpl::DeleteAudioDeviceProfile(std::string device_id,
                                              DeleteAudioDeviceProfileCallback callback) {
  if (tuned_device_specifications_.find(device_id) == tuned_device_specifications_.end()) {
    callback(ZX_OK);
    return;
  }

  auto default_device = GetDefaultDeviceSpecification(device_id);
  auto promise = context_.device_manager().UpdatePipelineConfig(
      device_id, default_device.pipeline_config, default_device.volume_curve);

  context_.threading_model().FidlDomain().executor()->schedule_task(promise.then(
      [this, device_id, callback = std::move(callback)](fit::result<void, zx_status_t>& result) {
        FX_CHECK(result.is_ok());
        tuned_device_specifications_.erase(device_id);
        callback(ZX_OK);
      }));
}

void AudioTunerImpl::SetAudioEffectConfig(std::string device_id,
                                          fuchsia::media::tuning::AudioEffectConfig effect,
                                          SetAudioEffectConfigCallback callback) {
  if (!effect.has_instance_name() || !effect.has_configuration()) {
    callback(ZX_ERR_BAD_STATE);
    return;
  }
  auto promise = context_.device_manager().UpdateDeviceEffect(device_id, effect.instance_name(),
                                                              effect.configuration());
  context_.threading_model().FidlDomain().executor()->schedule_task(
      promise.then([this, device_id, effect = std::move(effect), callback = std::move(callback)](
                       fit::result<void, fuchsia::media::audio::UpdateEffectError>& result) {
        if (result.is_ok()) {
          UpdateTunedDeviceSpecification(device_id, effect) ? callback(ZX_OK)
                                                            : callback(ZX_ERR_NOT_FOUND);
        } else if (result.error() == fuchsia::media::audio::UpdateEffectError::INVALID_CONFIG) {
          callback(ZX_ERR_BAD_STATE);
        } else {
          callback(ZX_ERR_NOT_FOUND);
        }
      }));
}

AudioTunerImpl::OutputDeviceSpecification AudioTunerImpl::GetDefaultDeviceSpecification(
    const std::string& device_id) {
  auto unique_id = AudioDevice::UniqueIdFromString(device_id).take_value();
  auto device_profile = context_.process_config().device_config().output_device_profile(unique_id);
  return OutputDeviceSpecification{.pipeline_config = device_profile.pipeline_config(),
                                   .volume_curve = device_profile.volume_curve()};
}

bool AudioTunerImpl::UpdateTunedDeviceSpecification(
    const std::string& device_id, const fuchsia::media::tuning::AudioEffectConfig& effect) {
  auto tuned_device_it = tuned_device_specifications_.find(device_id);
  if (tuned_device_it == tuned_device_specifications_.end()) {
    tuned_device_it =
        tuned_device_specifications_.emplace(device_id, GetDefaultDeviceSpecification(device_id))
            .first;
  }
  PipelineConfig::MixGroup& root = tuned_device_it->second.pipeline_config.mutable_root();
  return UpdateTunedEffectConfig(root, effect.instance_name(), effect.configuration());
}

bool AudioTunerImpl::UpdateTunedEffectConfig(PipelineConfig::MixGroup& root,
                                             const std::string& instance_name,
                                             const std::string& config) {
  for (PipelineConfig::Effect& effect : root.effects) {
    if (instance_name == effect.instance_name) {
      effect.effect_config = config;
      return true;
    }
  }
  for (PipelineConfig::MixGroup& mix_group : root.inputs) {
    if (UpdateTunedEffectConfig(mix_group, instance_name, config)) {
      return true;
    }
  }
  return false;
}

}  // namespace media::audio
