#pragma once

#include <cstdint>
#include <string>
#include <vector>

#include "core/audio_types.h"

namespace aptt {

struct DopConfig {
  std::uint32_t dsd_rate_multiplier = 64;
  std::uint32_t channel_count = 2;
  SampleType dsd_byte_order = SampleType::kDsd1BitLsbFirst;
  bool marker_starts_with_0x05 = true;
};

struct DopPackResult {
  bool ok = false;
  std::string error;
  FormatDescriptor carrier_format;
  std::vector<std::uint8_t> bytes;
};

struct DopSineConfig {
  DopConfig dop;
  double frequency_hz = 1000.0;
  double amplitude_dbfs = -20.0;
};

std::uint32_t DopCarrierSampleRateHz(std::uint32_t dsd_rate_multiplier);
bool IsSupportedDopRate(std::uint32_t dsd_rate_multiplier);
std::uint8_t DopMarkerForFrame(std::uint64_t frame_index,
                               bool marker_starts_with_0x05);
std::uint8_t DopIdleByte(SampleType dsd_byte_order);
FormatDescriptor MakeDopCarrierFormat(const DopConfig& config);

DopPackResult PackDopPayload(
    const DopConfig& config,
    const std::vector<std::vector<std::uint8_t>>& channel_payloads,
    std::uint64_t starting_dop_frame_index = 0);
DopPackResult GenerateDopSilence(const DopConfig& config,
                                 std::uint32_t dop_frame_count,
                                 std::uint64_t starting_dop_frame_index = 0);
DopPackResult GenerateDopTestPattern(const DopConfig& config,
                                     std::uint32_t dop_frame_count);

class DopSineGenerator {
 public:
  void Reset();
  DopPackResult GenerateSine(const DopSineConfig& config,
                             std::uint32_t dop_frame_count);
  DopPackResult GenerateSilence(const DopConfig& config,
                                std::uint32_t dop_frame_count);
  std::uint64_t next_dop_frame_index() const { return dop_frame_index_; }

 private:
  void EnsureChannelState(std::uint32_t channel_count);

  std::uint64_t dsd_bit_index_ = 0;
  std::uint64_t dop_frame_index_ = 0;
  std::vector<double> modulators_;
};

}  // namespace aptt
