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

#include "backends/directsound_pcm_backend.h"
#include "backends/directsound_device_discovery.h"

namespace {

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

aptt::PlaybackConfig MakeDirectSoundPcmConfig() {
  aptt::PlaybackConfig config;
  config.backend = aptt::BackendApi::kDirectSound;
  config.device.backend = aptt::BackendApi::kDirectSound;
  config.device.display_name = "Fixture DirectSound";
  config.device.stable_id = aptt::DirectSoundGuidStableIdFromText(
      "{01234567-89AB-CDEF-0123-456789ABCDEF}");
  config.device.driver_name = "DirectSound";
  config.device.is_known_problem_device = true;
  config.format =
      aptt::DirectSoundPcmCandidate(48000, aptt::SampleType::kInt16, 2);
  config.duration_ms = 1000;
  config.hold_mode = aptt::HoldMode::kKeepWarmAfterStop;
  config.release_cooldown_ms = 1000;
  return config;
}

void TestDirectSoundPolicyDefaultsAreConservative() {
  const auto config = MakeDirectSoundPcmConfig();
  const auto policy = aptt::MakeDirectSoundPcmPolicy(config);

  Expect(policy.requires_explicit_device, "explicit DirectSound device is required");
  Expect(policy.keep_warm_after_signal, "keep-warm is the default policy");
  Expect(!policy.release_after_drain, "release after drain is not default");
  Expect(!policy.uses_reset_on_normal_stop, "normal stop does not use reset");
  Expect(!policy.changes_cooperative_level_during_session,
         "cooperative level is not changed during a session");
  Expect(policy.restores_lost_buffers, "lost-buffer restore is enabled");
  Expect(policy.secondary_buffer_duration_ms >= 100,
         "secondary buffer duration is conservative");
  Expect(policy.cursor_poll_interval_ms > 0,
         "cursor polling interval is explicit");
}

void TestDirectSoundFormatGateAcceptsRenderablePcmFormats() {
  auto config = MakeDirectSoundPcmConfig();
  Expect(aptt::IsDirectSoundPcmPlaybackFormat(config.format),
         "int16 PCM is accepted");

  config.format = aptt::DirectSoundPcmCandidate(
      48000,
      aptt::SampleType::kInt24Packed,
      2);
  Expect(aptt::IsDirectSoundPcmPlaybackFormat(config.format),
         "packed 24-bit PCM is accepted");

  config.format = aptt::DirectSoundPcmCandidate(
      48000,
      aptt::SampleType::kInt24In32,
      2);
  Expect(aptt::IsDirectSoundPcmPlaybackFormat(config.format),
         "24-in-32 PCM is accepted");

  config.format.sample_type = aptt::SampleType::kFloat32;
  config.format.valid_bits_per_sample = 32;
  config.format.container_bits_per_sample = 32;
  Expect(aptt::IsDirectSoundPcmPlaybackFormat(config.format),
         "float32 PCM is accepted");

  config.format = aptt::DirectSoundPcmCandidate(
      48000,
      aptt::SampleType::kInt32,
      2);
  Expect(aptt::IsDirectSoundPcmPlaybackFormat(config.format),
         "int32 PCM is accepted");

  config.format.signal_mode = aptt::SignalMode::kDop;
  Expect(!aptt::IsDirectSoundPcmPlaybackFormat(config.format),
         "DoP is outside the DirectSound PCM task");
}

void TestDirectSoundInitializeRequiresExplicitDeviceBeforeApiUse() {
  auto config = MakeDirectSoundPcmConfig();
  config.device.stable_id.clear();

  aptt::DirectSoundPcmBackend backend;
  const auto result = backend.initialize(config);

  Expect(!result.ok, "initialize without DirectSound device fails");
  Expect(backend.lifecycle_state() == aptt::DeviceLifecycleState::kDiscovered,
         "missing DirectSound device fails before reserving a device");
  Expect(backend.diagnostic_events().empty(),
         "missing DirectSound device emits no real-device lifecycle events");
}

void TestDirectSoundInitializeRejectsForeignStableIdBeforeApiUse() {
  auto config = MakeDirectSoundPcmConfig();
  config.device.stable_id = "mme:waveout:1";

  aptt::DirectSoundPcmBackend backend;
  const auto result = backend.initialize(config);

  Expect(!result.ok, "foreign stable ID is rejected");
  Expect(backend.lifecycle_state() == aptt::DeviceLifecycleState::kDiscovered,
         "foreign stable ID fails before reserving a device");
  Expect(backend.diagnostic_events().empty(),
         "foreign stable ID emits no real-device lifecycle events");
}

void TestDirectSoundResetIsDisabled() {
  aptt::DirectSoundPcmBackend backend;
  const auto result = backend.reset();

  Expect(!result.ok, "reset is disabled");
  Expect(result.error.message.find("disabled") != std::string::npos,
         "reset failure explains lost-buffer restore policy");
}

}  // namespace

int main() {
  TestDirectSoundPolicyDefaultsAreConservative();
  TestDirectSoundFormatGateAcceptsRenderablePcmFormats();
  TestDirectSoundInitializeRequiresExplicitDeviceBeforeApiUse();
  TestDirectSoundInitializeRejectsForeignStableIdBeforeApiUse();
  TestDirectSoundResetIsDisabled();

  std::cout << "DirectSound PCM backend tests passed\n";
  return 0;
}
