#include <cstdlib>
#include <iostream>
#include <string_view>
#include <vector>

#include "core/native_dsd_generator.h"

namespace {

void Expect(bool condition, std::string_view message) {
  if (!condition) {
    std::cerr << "FAILED: " << message << "\n";
    std::exit(1);
  }
}

void TestRatesAndFormatDescriptor() {
  aptt::NativeDsdConfig config;
  config.dsd_rate_multiplier = 64;
  config.sample_type = aptt::SampleType::kDsd1BitLsbFirst;

  const auto format = aptt::MakeNativeDsdFormat(config);
  Expect(format.signal_mode == aptt::SignalMode::kAsioNativeDsd,
         "native DSD format has native DSD signal mode");
  Expect(format.sample_rate_hz == 2822400,
         "DSD64 native rate is 2.8224 MHz");
  Expect(format.sample_type == aptt::SampleType::kDsd1BitLsbFirst,
         "native DSD format preserves sample type");
  Expect(format.valid_bits_per_sample == 1,
         "1-bit native DSD has one valid bit");
  Expect(format.container_bits_per_sample == 8,
         "1-bit native DSD is byte-packed for ASIO buffers");
  Expect(format.dsd_rate_multiplier == 64,
         "native DSD format records DSD rate multiplier");

  Expect(aptt::NativeDsdRateHz(128) == 5644800,
         "DSD128 native rate is 5.6448 MHz");
  Expect(aptt::NativeDsdRateHz(256) == 11289600,
         "DSD256 native rate is 11.2896 MHz");
  Expect(aptt::NativeDsdRateHz(512) == 22579200,
         "DSD512 native rate is 22.5792 MHz");
  Expect(aptt::NativeDsdRateHz(1024) == 45158400,
         "DSD1024 native rate is 45.1584 MHz");
  Expect(aptt::NativeDsdRateHz(2048) == 90316800,
         "DSD2048 native rate is 90.3168 MHz");
  Expect(aptt::NativeDsdRateHz(4096) == 0,
         "unsupported DSD4096 rate returns zero");
}

void TestIdlePatternsAreFormatCorrect() {
  aptt::NativeDsdConfig config;
  config.channel_count = 2;
  config.sample_type = aptt::SampleType::kDsd1BitLsbFirst;
  auto idle = aptt::GenerateNativeDsdIdle(config, 4);
  Expect(idle.ok, "LSB native DSD idle generation succeeds");
  Expect((idle.channel_payloads[0] ==
          std::vector<std::uint8_t>{0x69, 0x69, 0x69, 0x69}),
         "LSB native DSD idle uses 0x69");

  config.sample_type = aptt::SampleType::kDsd1BitMsbFirst;
  idle = aptt::GenerateNativeDsdIdle(config, 4);
  Expect(idle.ok, "MSB native DSD idle generation succeeds");
  Expect((idle.channel_payloads[0] ==
          std::vector<std::uint8_t>{0x96, 0x96, 0x96, 0x96}),
         "MSB native DSD idle uses 0x96");

  config.sample_type = aptt::SampleType::kDsd8Bit;
  idle = aptt::GenerateNativeDsdIdle(config, 4);
  Expect(idle.ok, "NER8 native DSD idle generation succeeds");
  Expect((idle.channel_payloads[0] ==
          std::vector<std::uint8_t>{0x00, 0x01, 0x00, 0x01}),
         "NER8 native DSD idle uses explicit alternating density");
}

void TestSampleTypeNamesAndByteOrderNames() {
  Expect(std::string_view(aptt::NativeDsdSampleTypeName(
             aptt::SampleType::kDsd1BitLsbFirst)) == "ASIOSTDSDInt8LSB1",
         "LSB native DSD sample type name is explicit");
  Expect(std::string_view(aptt::NativeDsdSampleTypeName(
             aptt::SampleType::kDsd1BitMsbFirst)) == "ASIOSTDSDInt8MSB1",
         "MSB native DSD sample type name is explicit");
  Expect(std::string_view(aptt::NativeDsdSampleTypeName(
             aptt::SampleType::kDsd8Bit)) == "ASIOSTDSDInt8NER8",
         "NER8 native DSD sample type name is explicit");
  Expect(std::string_view(aptt::NativeDsdByteOrderName(
             aptt::SampleType::kDsd1BitMsbFirst)) == "msb-first",
         "native DSD byte order name is explicit");
}

void TestTestPatternIsDeterministicAndChannelSpecific() {
  aptt::NativeDsdConfig config;
  config.channel_count = 2;
  const auto pattern = aptt::GenerateNativeDsdTestPattern(config, 4);

  Expect(pattern.ok, "native DSD test pattern generation succeeds");
  Expect(pattern.channel_payloads.size() == 2,
         "native DSD test pattern has two channels");
  Expect((pattern.channel_payloads[0] ==
          std::vector<std::uint8_t>{0x00, 0x11, 0x22, 0x33}),
         "left native DSD test pattern is deterministic");
  Expect((pattern.channel_payloads[1] ==
          std::vector<std::uint8_t>{0x31, 0x42, 0x53, 0x64}),
         "right native DSD test pattern is channel-specific");
}

void TestSineGenerationIsDeterministicAndNotIdle() {
  aptt::NativeDsdSineConfig config;
  config.dsd.channel_count = 2;
  config.dsd.sample_type = aptt::SampleType::kDsd1BitLsbFirst;
  config.frequency_hz = 1000.0;
  config.amplitude_dbfs = -20.0;

  aptt::NativeDsdSineGenerator first;
  aptt::NativeDsdSineGenerator second;
  const auto first_result = first.GenerateSine(config, 16);
  const auto second_result = second.GenerateSine(config, 16);
  const auto idle = aptt::GenerateNativeDsdIdle(config.dsd, 16);

  Expect(first_result.ok, "native DSD sine generation succeeds");
  Expect(first_result.channel_payloads == second_result.channel_payloads,
         "native DSD sine generation is deterministic");
  Expect(first_result.channel_payloads != idle.channel_payloads,
         "native DSD sine differs from idle pattern");
}

void TestUnsupportedCombinationsFailClearly() {
  aptt::NativeDsdConfig unsupported_rate;
  unsupported_rate.dsd_rate_multiplier = 4096;
  Expect(!aptt::GenerateNativeDsdIdle(unsupported_rate, 1).ok,
         "unsupported native DSD rate fails");

  aptt::NativeDsdConfig no_channels;
  no_channels.channel_count = 0;
  Expect(!aptt::GenerateNativeDsdIdle(no_channels, 1).ok,
         "zero channel native DSD config fails");

  aptt::NativeDsdSineConfig invalid_signal;
  invalid_signal.frequency_hz = 0.0;
  aptt::NativeDsdSineGenerator generator;
  Expect(!generator.GenerateSine(invalid_signal, 1).ok,
         "invalid native DSD sine frequency fails");
}

}  // namespace

int main() {
  TestRatesAndFormatDescriptor();
  TestIdlePatternsAreFormatCorrect();
  TestSampleTypeNamesAndByteOrderNames();
  TestTestPatternIsDeterministicAndChannelSpecific();
  TestSineGenerationIsDeterministicAndNotIdle();
  TestUnsupportedCombinationsFailClearly();

  std::cout << "native DSD generator tests passed\n";
  return 0;
}
