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

#include "backends/wasapi_error.h"
#include "backends/wasapi_shared_pcm_backend.h"

namespace {

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

aptt::PlaybackConfig MakeSharedPcmConfig() {
  aptt::PlaybackConfig config;
  config.backend = aptt::BackendApi::kWasapiShared;
  config.device.backend = aptt::BackendApi::kWasapiShared;
  config.device.display_name = "Fixture WASAPI endpoint";
  config.device.stable_id = "fixture-endpoint";
  config.device.driver_name = "WASAPI/Core Audio";
  config.device.is_known_problem_device = true;
  config.format.signal_mode = aptt::SignalMode::kPcm;
  config.format.sample_rate_hz = 48000;
  config.format.sample_type = aptt::SampleType::kFloat32;
  config.format.valid_bits_per_sample = 32;
  config.format.container_bits_per_sample = 32;
  config.format.channels.channel_count = 2;
  config.format.channels.channel_mask = 3;
  config.duration_ms = 1000;
  config.hold_mode = aptt::HoldMode::kKeepWarmAfterStop;
  config.release_cooldown_ms = 1000;
  return config;
}

void TestPolicyDefaultsAreConservative() {
  const auto config = MakeSharedPcmConfig();
  const auto policy = aptt::MakeWasapiSharedPcmPolicy(config);

  Expect(policy.requires_explicit_endpoint, "explicit endpoint is required");
  Expect(policy.keep_warm_after_signal, "keep-warm is the default policy");
  Expect(!policy.release_after_drain, "release after drain is not the default");
  Expect(!policy.uses_reset_on_normal_stop, "normal stop does not use Reset");
  Expect(!policy.uses_fallback_endpoint, "fallback endpoint is disabled");
  Expect(!policy.uses_fallback_format, "fallback format is disabled");
  Expect(policy.buffer_duration_ms == 100, "buffer duration is conservative");
}

void TestFormatGateAcceptsRenderablePcmFormats() {
  auto config = MakeSharedPcmConfig();
  Expect(aptt::IsWasapiSharedPcmPlaybackFormat(config.format),
         "float32 PCM is accepted");

  config.format.sample_type = aptt::SampleType::kInt16;
  config.format.valid_bits_per_sample = 16;
  config.format.container_bits_per_sample = 16;
  Expect(aptt::IsWasapiSharedPcmPlaybackFormat(config.format),
         "int16 PCM is accepted");

  config.format.sample_type = aptt::SampleType::kInt24Packed;
  config.format.valid_bits_per_sample = 24;
  config.format.container_bits_per_sample = 24;
  Expect(aptt::IsWasapiSharedPcmPlaybackFormat(config.format),
         "packed 24-bit PCM is accepted");

  config.format.sample_type = aptt::SampleType::kInt24In32;
  config.format.valid_bits_per_sample = 24;
  config.format.container_bits_per_sample = 32;
  Expect(aptt::IsWasapiSharedPcmPlaybackFormat(config.format),
         "24-in-32 PCM is accepted");

  config.format.sample_type = aptt::SampleType::kInt32;
  config.format.valid_bits_per_sample = 32;
  config.format.container_bits_per_sample = 32;
  Expect(aptt::IsWasapiSharedPcmPlaybackFormat(config.format),
         "int32 PCM is accepted");

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

void TestInitializeRequiresEndpointBeforeApiUse() {
  auto config = MakeSharedPcmConfig();
  config.device.stable_id.clear();

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

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

void TestResetIsDisabledForSharedPlayback() {
  aptt::WasapiSharedPcmBackend backend;
  const auto result = backend.reset();

  Expect(!result.ok, "reset is disabled");
  Expect(result.error.message.find("disabled") != std::string::npos,
         "reset failure explains the drain/keep-warm lifecycle");
}

void TestWasapiDeviceInUseErrorIsActionable() {
  const int device_in_use = static_cast<int>(0x8889000Au);

  Expect(std::string_view(aptt::WasapiAudioClientErrorSymbol(device_in_use)) ==
             "AUDCLNT_E_DEVICE_IN_USE",
         "device-in-use HRESULT is decoded");

  const auto message = aptt::DescribeWasapiAudioClientError(
      device_in_use,
      "IAudioClient::Initialize",
      "failed to initialize WASAPI shared stream");
  Expect(message.find("AUDCLNT_E_DEVICE_IN_USE") != std::string::npos,
         "message includes HRESULT symbol");
  Expect(message.find("already in use") != std::string::npos,
         "message explains endpoint occupation");
  Expect(message.find("exclusive-mode") != std::string::npos,
         "message points to common exclusive-mode cause");
}

}  // namespace

int main() {
  TestPolicyDefaultsAreConservative();
  TestFormatGateAcceptsRenderablePcmFormats();
  TestInitializeRequiresEndpointBeforeApiUse();
  TestResetIsDisabledForSharedPlayback();
  TestWasapiDeviceInUseErrorIsActionable();

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