#include "backends/directsound_pcm_backend.h"

#include <algorithm>
#include <atomic>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <cstring>
#include <limits>
#include <mutex>
#include <sstream>
#include <string_view>
#include <thread>
#include <utility>

#include "backends/audio_thread_scheduling.h"
#include "backends/directsound_device_discovery.h"
#include "core/high_load_diagnostics.h"
#include "core/pcm_sample_conversion.h"
#include "core/signal_generator.h"

#if defined(_WIN32)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#include <mmsystem.h>
#include <dsound.h>
#include <mmreg.h>
#ifndef WAVE_FORMAT_IEEE_FLOAT
#define WAVE_FORMAT_IEEE_FLOAT 0x0003
#endif
#endif

namespace aptt {
namespace {

constexpr int kDirectSoundInvalidArgument = 0x40001;
constexpr int kDirectSoundInvalidState = 0x40002;
constexpr int kDirectSoundNotInitialized = 0x40003;
constexpr int kDirectSoundResetDisabled = 0x40004;
constexpr int kDirectSoundNotImplemented =
    static_cast<int>(static_cast<std::int32_t>(0x80004001u));

bool LooksLikeDirectSoundStableId(const std::string& stable_id) {
  if (stable_id == DirectSoundDefaultStableId() || stable_id == "dsound:default") {
    return true;
  }
  constexpr std::string_view kPrefix = "directsound:";
  constexpr std::string_view kLegacyPrefix = "dsound:";
  const bool prefixed = stable_id.rfind(kPrefix, 0) == 0 ||
                        stable_id.rfind(kLegacyPrefix, 0) == 0;
  return prefixed && stable_id.find('{') != std::string::npos &&
         stable_id.find('}') != std::string::npos;
}

OperationResult ValidateConfigForPlayback(const PlaybackConfig& config) {
  if (config.backend != BackendApi::kDirectSound) {
    return OperationResult::Failure(
        kDirectSoundInvalidArgument,
        "DirectSound PCM playback requires BackendApi::kDirectSound");
  }
  if (config.device.stable_id.empty()) {
    return OperationResult::Failure(
        kDirectSoundInvalidArgument,
        "DirectSound PCM playback requires an explicit DirectSound device ID");
  }
  if (!LooksLikeDirectSoundStableId(config.device.stable_id)) {
    return OperationResult::Failure(
        kDirectSoundInvalidArgument,
        "DirectSound PCM playback requires directsound:default or directsound:{GUID}");
  }
  if (!IsDirectSoundPcmPlaybackFormat(config.format)) {
    return OperationResult::Failure(
        kDirectSoundInvalidArgument,
        "DirectSound playback requires a renderable PCM format");
  }
  if (config.format.sample_rate_hz == 0 ||
      config.format.channels.channel_count == 0) {
    return OperationResult::Failure(
        kDirectSoundInvalidArgument,
        "DirectSound PCM playback requires a non-zero sample rate and channel count");
  }
  return OperationResult::Success();
}

std::uint64_t DurationFrames(const PlaybackConfig& config) {
  if (config.continuous) {
    return std::numeric_limits<std::uint64_t>::max();
  }
  return std::max<std::uint64_t>(
      1,
      (static_cast<std::uint64_t>(config.format.sample_rate_hz) *
       config.duration_ms) /
          1000);
}

std::string FormatSummary(const FormatDescriptor& format) {
  std::ostringstream summary;
  summary << format.sample_rate_hz << " Hz "
          << format.channels.channel_count << " ch "
          << ToString(format.sample_type) << " valid_bits="
          << format.valid_bits_per_sample << " container_bits="
          << format.container_bits_per_sample;
  return summary.str();
}

#if defined(_WIN32)

int HResultCode(HRESULT result) {
  return static_cast<int>(static_cast<std::int32_t>(result));
}

template <typename T>
void SafeRelease(T*& ptr) {
  if (ptr != nullptr) {
    ptr->Release();
    ptr = nullptr;
  }
}

std::wstring Utf8ToWide(const std::string& value) {
  if (value.empty()) {
    return {};
  }
  const int required = MultiByteToWideChar(
      CP_UTF8, 0, value.c_str(), -1, nullptr, 0);
  if (required <= 1) {
    return {};
  }
  std::wstring converted(static_cast<std::size_t>(required - 1), L'\0');
  MultiByteToWideChar(
      CP_UTF8, 0, value.c_str(), -1, converted.data(), required);
  return converted;
}

struct DirectSoundDeviceKey {
  bool valid = false;
  bool is_default = false;
  GUID guid{};
};

DirectSoundDeviceKey ParseDirectSoundStableId(const std::string& stable_id) {
  if (stable_id == DirectSoundDefaultStableId() || stable_id == "dsound:default") {
    return DirectSoundDeviceKey{.valid = true, .is_default = true};
  }

  constexpr std::string_view kPrefix = "directsound:";
  constexpr std::string_view kLegacyPrefix = "dsound:";
  std::string guid_text;
  if (stable_id.rfind(kPrefix, 0) == 0) {
    guid_text = stable_id.substr(kPrefix.size());
  } else if (stable_id.rfind(kLegacyPrefix, 0) == 0) {
    guid_text = stable_id.substr(kLegacyPrefix.size());
  } else {
    return {};
  }

  const std::wstring wide_guid = Utf8ToWide(guid_text);
  GUID guid{};
  if (FAILED(CLSIDFromString(wide_guid.c_str(), &guid))) {
    return {};
  }
  return DirectSoundDeviceKey{
      .valid = true,
      .is_default = false,
      .guid = guid,
  };
}

constexpr GUID kWaveSubtypePcm = {
    0x00000001,
    0x0000,
    0x0010,
    {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71},
};

constexpr GUID kWaveSubtypeIeeeFloat = {
    0x00000003,
    0x0000,
    0x0010,
    {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71},
};

bool RequiresExtensibleWaveFormat(const FormatDescriptor& descriptor) {
  return descriptor.sample_type == SampleType::kInt24In32 ||
         descriptor.channels.channel_mask != 0;
}

WAVEFORMATEXTENSIBLE WaveFormatFromDescriptor(
    const FormatDescriptor& descriptor) {
  WAVEFORMATEXTENSIBLE wave{};
  wave.Format.wFormatTag = RequiresExtensibleWaveFormat(descriptor)
                               ? WAVE_FORMAT_EXTENSIBLE
                               : descriptor.sample_type == SampleType::kFloat32
                                     ? WAVE_FORMAT_IEEE_FLOAT
                                     : WAVE_FORMAT_PCM;
  wave.Format.nChannels = static_cast<WORD>(descriptor.channels.channel_count);
  wave.Format.nSamplesPerSec = descriptor.sample_rate_hz;
  wave.Format.wBitsPerSample =
      static_cast<WORD>(descriptor.container_bits_per_sample);
  wave.Format.nBlockAlign =
      static_cast<WORD>((wave.Format.nChannels * wave.Format.wBitsPerSample) / 8);
  wave.Format.nAvgBytesPerSec =
      wave.Format.nSamplesPerSec * wave.Format.nBlockAlign;
  if (wave.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
    wave.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
    wave.Samples.wValidBitsPerSample =
        static_cast<WORD>(descriptor.valid_bits_per_sample);
    wave.dwChannelMask = descriptor.channels.channel_mask;
    wave.SubFormat = descriptor.sample_type == SampleType::kFloat32
                         ? kWaveSubtypeIeeeFloat
                         : kWaveSubtypePcm;
  } else {
    wave.Format.cbSize = 0;
  }
  return wave;
}

#endif

}  // namespace

DirectSoundPcmPolicy MakeDirectSoundPcmPolicy(const PlaybackConfig& config) {
  DirectSoundPcmPolicy policy;
  policy.keep_warm_after_signal =
      config.hold_mode == HoldMode::kKeepWarmAfterStop;
  policy.release_after_drain =
      config.hold_mode == HoldMode::kReleaseAfterDrain;
  policy.secondary_buffer_duration_ms = std::max<std::uint32_t>(
      50,
      config.directsound_secondary_buffer_duration_ms);
  policy.write_chunk_ms = std::max<std::uint32_t>(
      1,
      config.directsound_write_chunk_ms);
  policy.cursor_poll_interval_ms = std::max<std::uint32_t>(
      1,
      config.directsound_cursor_poll_interval_ms);
  policy.release_cooldown_ms = config.release_cooldown_ms == 0
                                   ? 1
                                   : config.release_cooldown_ms;
  return policy;
}

bool IsDirectSoundPcmPlaybackFormat(const FormatDescriptor& format) {
  return IsRenderablePcmFormat(format);
}

struct DirectSoundPcmBackend::Impl {
  ~Impl() { Shutdown(); }

  BackendApi Api() const { return BackendApi::kDirectSound; }

  DeviceList EnumerateDevices() {
    DeviceList devices;
    const auto snapshot = EnumerateDirectSoundOutputDevices();
    devices.reserve(snapshot.devices.size());
    for (const auto& device_snapshot : snapshot.devices) {
      devices.push_back(device_snapshot.device);
    }
    return devices;
  }

  FormatProbeResult ProbeFormats(const DeviceInfo& device) {
    FormatProbeResult result;
    result.requested = DirectSoundDefaultPcmCandidates().front();
    if (!LooksLikeDirectSoundStableId(device.stable_id)) {
      result.rejection_reasons.push_back(
          "DirectSound format probe requires an explicit DirectSound stable ID");
      return result;
    }

    DirectSoundFormatProbeRequest request;
    request.stable_id = device.stable_id;
    request.candidate_formats = DirectSoundDefaultPcmCandidates();
    const auto snapshot = ProbeDirectSoundDeviceFormats(request);
    for (const auto& probe : snapshot.probes) {
      if (probe.accepted_format) {
        result.supported_formats.push_back(*probe.accepted_format);
      }
      if (probe.error) {
        result.rejection_reasons.push_back(probe.error->message);
      }
    }
    return result;
  }

  OperationResult Initialize(const PlaybackConfig& config) {
    auto validation = ValidateConfigForPlayback(config);
    if (!validation.ok) {
      SetLastError(validation.error);
      return validation;
    }

    Shutdown();

    {
      std::scoped_lock lock(state_mutex_, stats_mutex_, events_mutex_);
      config_ = config;
      policy_ = MakeDirectSoundPcmPolicy(config_);
      stats_ = {};
      events_.clear();
      sequence_ = 0;
      state_ = DeviceLifecycleState::kDiscovered;
      signal_frame_target_ = DurationFrames(config_);
      signal_frames_written_ = 0;
      force_silence_ = false;
      render_thread_stop_ = false;
      generator_.ResetPhase();
      last_error_ = {};
    }

    if (!TransitionTo(DeviceLifecycleState::kReserved,
                      "selected DirectSound device reserved")) {
      return OperationResult::Failure(
          kDirectSoundInvalidState,
          GetLastError().message);
    }

#if !defined(_WIN32)
    TransitionTo(DeviceLifecycleState::kFaulted,
                 "DirectSound playback is not available");
    return Fail(
        kDirectSoundNotImplemented,
        "DirectSound playback is available only on Windows");
#else
    const auto device_key = ParseDirectSoundStableId(config_.device.stable_id);
    if (!device_key.valid) {
      TransitionTo(DeviceLifecycleState::kFaulted,
                   "DirectSound stable ID parse failed");
      return Fail(
          kDirectSoundInvalidArgument,
          "invalid DirectSound stable ID");
    }

    const GUID* guid = device_key.is_default ? nullptr : &device_key.guid;
    HRESULT result = DirectSoundCreate(guid, &direct_sound_, nullptr);
    if (FAILED(result) || direct_sound_ == nullptr) {
      TransitionTo(DeviceLifecycleState::kFaulted,
                   "DirectSoundCreate failed");
      ReleaseInterfaces();
      return Fail(
          HResultCode(result),
          "failed to create DirectSound device for playback");
    }

    result = direct_sound_->SetCooperativeLevel(GetDesktopWindow(), DSSCL_NORMAL);
    if (FAILED(result)) {
      TransitionTo(DeviceLifecycleState::kFaulted,
                   "DirectSound SetCooperativeLevel failed");
      ReleaseInterfaces();
      return Fail(
          HResultCode(result),
          "failed to set DirectSound cooperative level");
    }

    wave_format_ = WaveFormatFromDescriptor(config_.format);
    buffer_frames_ = std::max<std::uint32_t>(
        256,
        (config_.format.sample_rate_hz *
         policy_.secondary_buffer_duration_ms) /
            1000);
    chunk_frames_ = std::max<std::uint32_t>(
        32,
        (config_.format.sample_rate_hz * policy_.write_chunk_ms) / 1000);
    const std::uint32_t max_chunk_frames =
        std::max<std::uint32_t>(1, buffer_frames_ / 2);
    chunk_frames_ = std::min(chunk_frames_, max_chunk_frames);
    buffer_bytes_ = buffer_frames_ * wave_format_.Format.nBlockAlign;
    chunk_bytes_ = chunk_frames_ * wave_format_.Format.nBlockAlign;

    DSBUFFERDESC buffer_desc{};
    buffer_desc.dwSize = sizeof(buffer_desc);
    buffer_desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2;
    buffer_desc.dwBufferBytes = buffer_bytes_;
    buffer_desc.lpwfxFormat = &wave_format_.Format;
    result = direct_sound_->CreateSoundBuffer(
        &buffer_desc,
        &secondary_buffer_,
        nullptr);
    if (FAILED(result) || secondary_buffer_ == nullptr) {
      TransitionTo(DeviceLifecycleState::kFaulted,
                   "DirectSound secondary buffer creation failed");
      ReleaseInterfaces();
      return Fail(
          HResultCode(result),
          "failed to create DirectSound secondary buffer");
    }

    {
      std::lock_guard lock(stats_mutex_);
      stats_.expected_callback_interval_ms =
          1000.0 * static_cast<double>(chunk_frames_) /
          static_cast<double>(config_.format.sample_rate_hz);
    }

    if (!TransitionTo(DeviceLifecycleState::kPrepared,
                      "DirectSound secondary buffer prepared once")) {
      ReleaseInterfaces();
      return OperationResult::Failure(
          kDirectSoundInvalidState,
          GetLastError().message);
    }
    AddInitializationEvent();
    return OperationResult::Success();
#endif
  }

  OperationResult Start() {
#if !defined(_WIN32)
    return Fail(
        kDirectSoundNotImplemented,
        "DirectSound playback is available only on Windows");
#else
    const auto current = GetState();
    if (current == DeviceLifecycleState::kRunningSilence &&
        render_thread_.joinable()) {
      return Fail(
          kDirectSoundInvalidState,
          "DirectSound RunningSilence restart requires explicit release before rerun");
    }
    if (current != DeviceLifecycleState::kPrepared &&
        current != DeviceLifecycleState::kHeldOpen) {
      return Fail(
          kDirectSoundInvalidState,
          "DirectSound secondary buffer must be prepared before start");
    }
    if (secondary_buffer_ == nullptr) {
      return Fail(
          kDirectSoundNotInitialized,
          "DirectSound secondary buffer is not initialized");
    }

    force_silence_ = false;
    render_thread_stop_ = false;
    signal_frames_written_ = 0;
    generator_.ResetPhase();
    last_callback_time_ = std::chrono::steady_clock::now();

    if (!FillBufferRegion(0, buffer_bytes_, "initial DirectSound buffer fill")) {
      TransitionTo(DeviceLifecycleState::kFaulted,
                   "initial DirectSound buffer fill failed");
      return OperationResult::Failure(
          kDirectSoundInvalidState,
          GetLastError().message);
    }

    HRESULT result = secondary_buffer_->SetCurrentPosition(0);
    if (FAILED(result)) {
      TransitionTo(DeviceLifecycleState::kFaulted,
                   "DirectSound SetCurrentPosition failed");
      return Fail(
          HResultCode(result),
          "failed to reset DirectSound play cursor");
    }

    if (!TransitionTo(DeviceLifecycleState::kRunningSignal,
                      "DirectSound 1 kHz signal started")) {
      return OperationResult::Failure(
          kDirectSoundInvalidState,
          GetLastError().message);
    }

    result = secondary_buffer_->Play(0, 0, DSBPLAY_LOOPING);
    if (FAILED(result)) {
      TransitionTo(DeviceLifecycleState::kFaulted,
                   "DirectSound secondary buffer Play failed");
      return Fail(
          HResultCode(result),
          "failed to start DirectSound secondary buffer");
    }

    render_thread_ = std::thread([this] { RenderLoop(); });
    return OperationResult::Success();
#endif
  }

  OperationResult Stop() {
    const auto current = GetState();
    if (current == DeviceLifecycleState::kRunningSignal &&
        policy_.keep_warm_after_signal) {
      force_silence_ = true;
      if (!TransitionTo(DeviceLifecycleState::kRunningSilence,
                        "normal DirectSound stop switched to PCM silence")) {
        return OperationResult::Failure(
            kDirectSoundInvalidState,
            GetLastError().message);
      }
      return OperationResult::Success();
    }
    if (current == DeviceLifecycleState::kRunningSilence &&
        policy_.keep_warm_after_signal) {
      return OperationResult::Success();
    }

    if (current == DeviceLifecycleState::kRunningSignal ||
        current == DeviceLifecycleState::kRunningSilence) {
      if (!TransitionTo(DeviceLifecycleState::kDraining,
                        "DirectSound playback draining before stop")) {
        return OperationResult::Failure(
            kDirectSoundInvalidState,
            GetLastError().message);
      }
      StopRenderThread();
#if defined(_WIN32)
      if (secondary_buffer_ != nullptr) {
        const HRESULT result = secondary_buffer_->Stop();
        if (FAILED(result)) {
          TransitionTo(DeviceLifecycleState::kFaulted,
                       "DirectSound Stop failed");
          return Fail(
              HResultCode(result),
              "failed to stop DirectSound secondary buffer");
        }
      }
#endif
    }

    if (policy_.release_after_drain) {
      return ReleaseAfterDrain();
    }
    if (GetState() != DeviceLifecycleState::kHeldOpen) {
      if (!TransitionTo(DeviceLifecycleState::kHeldOpen,
                        "DirectSound secondary buffer held after stop")) {
        return OperationResult::Failure(
            kDirectSoundInvalidState,
            GetLastError().message);
      }
    }
    return OperationResult::Success();
  }

  OperationResult Reset() {
    return Fail(
        kDirectSoundResetDisabled,
        "DirectSound reset is disabled; lost buffers are restored conservatively");
  }

  RealtimeStats GetRealtimeStats() const {
    std::lock_guard lock(stats_mutex_);
    return stats_;
  }

  BackendError GetLastError() const {
    std::lock_guard lock(error_mutex_);
    return last_error_;
  }

  OperationResult Shutdown() {
    const auto current = GetState();
    if (current == DeviceLifecycleState::kDiscovered ||
        current == DeviceLifecycleState::kReleased) {
      return OperationResult::Success();
    }

    if (current == DeviceLifecycleState::kRunningSignal ||
        current == DeviceLifecycleState::kRunningSilence) {
      if (!TransitionTo(DeviceLifecycleState::kDraining,
                        "DirectSound playback draining before release")) {
        return OperationResult::Failure(
            kDirectSoundInvalidState,
            GetLastError().message);
      }
    }
    StopRenderThread();
#if defined(_WIN32)
    if (secondary_buffer_ != nullptr) {
      secondary_buffer_->Stop();
    }
#endif
    return ReleaseAfterDrain();
  }

  DeviceLifecycleState GetState() const {
    std::lock_guard lock(state_mutex_);
    return state_;
  }

  std::vector<DiagnosticEvent> GetEvents() const {
    std::lock_guard lock(events_mutex_);
    return events_;
  }

 private:
  OperationResult Fail(int code, std::string message) {
    SetLastError({code, std::move(message)});
    return OperationResult::Failure(code, GetLastError().message);
  }

  void SetLastError(BackendError error) {
    std::lock_guard lock(error_mutex_);
    last_error_ = std::move(error);
  }

  bool TransitionTo(DeviceLifecycleState next, std::string message) {
    DeviceLifecycleState previous;
    {
      std::lock_guard lock(state_mutex_);
      previous = state_;
      LifecyclePolicy lifecycle_policy;
      lifecycle_policy.known_problem_device =
          config_.device.is_known_problem_device;
      const auto decision = EvaluateTransition(previous, next, lifecycle_policy);
      if (!decision.allowed) {
        SetLastError({kDirectSoundInvalidState, decision.reason});
        return false;
      }
      state_ = next;
    }

    auto event = MakeLifecycleEvent(
        NextSequence(),
        BackendApi::kDirectSound,
        config_.device.stable_id,
        previous,
        next,
        std::move(message));
    event.backend_fields["hold_mode"] = ToString(config_.hold_mode);
    event.backend_fields["reset_used"] = "false";
    event.backend_fields["cooperative_level_changed"] = "false";
    AppendEvent(std::move(event));
    SetLastError({});
    return true;
  }

  std::uint64_t NextSequence() { return ++sequence_; }

  void AppendEvent(DiagnosticEvent event) {
    std::lock_guard lock(events_mutex_);
    events_.push_back(std::move(event));
  }

  void AddInitializationEvent() {
    DiagnosticEvent event;
    event.type = DiagnosticEventType::kFormatProbe;
    event.sequence = NextSequence();
    event.backend = BackendApi::kDirectSound;
    event.device_id = config_.device.stable_id;
    event.format = config_.format;
    event.message = "DirectSound PCM secondary buffer initialized";
    event.backend_fields["requested_format"] = FormatSummary(config_.format);
    event.backend_fields["accepted_format"] = FormatSummary(config_.format);
    event.backend_fields["cooperative_level"] = "DSSCL_NORMAL";
    event.backend_fields["cooperative_level_set_once"] = "true";
    event.backend_fields["secondary_buffer_frames"] =
        std::to_string(buffer_frames_);
    event.backend_fields["secondary_buffer_bytes"] =
        std::to_string(buffer_bytes_);
    event.backend_fields["secondary_buffer_duration_ms"] =
        std::to_string(policy_.secondary_buffer_duration_ms);
    event.backend_fields["write_chunk_frames"] = std::to_string(chunk_frames_);
    event.backend_fields["write_chunk_bytes"] = std::to_string(chunk_bytes_);
    event.backend_fields["cursor_poll_interval_ms"] =
        std::to_string(policy_.cursor_poll_interval_ms);
    event.backend_fields["restore_lost_buffers"] =
        policy_.restores_lost_buffers ? "true" : "false";
    event.backend_fields["audio_thread_mmcss_enabled"] =
        config_.audio_thread_mmcss_enabled ? "true" : "false";
    event.backend_fields["audio_thread_mmcss_task_name"] =
        config_.audio_thread_mmcss_task_name;
    event.backend_fields["audio_thread_mmcss_priority"] =
        std::to_string(config_.audio_thread_mmcss_priority);
    AddHighLoadDiagnosticFields(config_, event.backend_fields);
    AppendEvent(std::move(event));
  }

  void AddThreadSchedulingEvent(
      const AudioThreadMmcssRegistrationSnapshot& snapshot,
      std::string message) {
    DiagnosticEvent event;
    event.type = DiagnosticEventType::kRuntimeStats;
    event.sequence = NextSequence();
    event.backend = BackendApi::kDirectSound;
    event.device_id = config_.device.stable_id;
    event.message = std::move(message);
    event.backend_fields["api"] = "AvSetMmThreadCharacteristics";
    event.backend_fields["thread_role"] = "DirectSound cursor/write thread";
    AddAudioThreadMmcssBackendFields(event.backend_fields, snapshot);
    AppendEvent(std::move(event));
  }

  void AddRuntimeEvent(std::uint32_t play_cursor,
                       std::uint32_t write_cursor,
                       double lock_duration_ms,
                       std::uint32_t submitted_frames) {
    const auto stats = GetRealtimeStats();
    if (stats.callback_count > 8 && (stats.callback_count % 50) != 0) {
      return;
    }

    DiagnosticEvent event;
    event.type = DiagnosticEventType::kRuntimeStats;
    event.sequence = NextSequence();
    event.backend = BackendApi::kDirectSound;
    event.device_id = config_.device.stable_id;
    event.message = "DirectSound cursor/write update";
    event.realtime_stats = stats;
    event.backend_fields["play_cursor_bytes"] = std::to_string(play_cursor);
    event.backend_fields["write_cursor_bytes"] = std::to_string(write_cursor);
    event.backend_fields["lock_duration_ms"] = std::to_string(lock_duration_ms);
    event.backend_fields["submitted_frames"] = std::to_string(submitted_frames);
    AddHighLoadDiagnosticFields(config_, event.backend_fields);
    if (HighLoadLateCallbackJustOccurred(config_, stats)) {
      event.backend_fields["late_callback"] = "true";
      event.backend_fields["late_callback_source"] =
          "high_load_render_delay";
    }
    AppendEvent(std::move(event));
  }

  void AddErrorEvent(int code, std::string api, std::string message) {
    DiagnosticEvent event;
    event.type = DiagnosticEventType::kError;
    event.sequence = NextSequence();
    event.backend = BackendApi::kDirectSound;
    event.device_id = config_.device.stable_id;
    event.message = std::move(message);
    event.backend_fields["api"] = std::move(api);
    event.backend_fields["code"] = std::to_string(code);
    event.backend_fields["symbol"] = DirectSoundResultSymbol(code);
    AppendEvent(std::move(event));
  }

#if defined(_WIN32)
  bool FillBufferRegion(std::uint32_t offset,
                        std::uint32_t bytes,
                        const char* reason) {
    if (secondary_buffer_ == nullptr || bytes == 0) {
      return true;
    }

    void* first = nullptr;
    void* second = nullptr;
    DWORD first_bytes = 0;
    DWORD second_bytes = 0;
    const auto before = std::chrono::steady_clock::now();
    HRESULT result = secondary_buffer_->Lock(
        offset,
        bytes,
        &first,
        &first_bytes,
        &second,
        &second_bytes,
        0);
    if (result == DSERR_BUFFERLOST && RestoreLostBuffer("Lock")) {
      result = secondary_buffer_->Lock(
          offset,
          bytes,
          &first,
          &first_bytes,
          &second,
          &second_bytes,
          0);
    }
    if (FAILED(result)) {
      AddErrorEvent(
          HResultCode(result),
          "IDirectSoundBuffer::Lock",
          std::string(reason) + " failed");
      SetLastError({HResultCode(result), "DirectSound Lock failed"});
      return false;
    }

    const std::uint32_t frames_written =
        FillLockedRegions(first, first_bytes, second, second_bytes);
    result = secondary_buffer_->Unlock(first, first_bytes, second, second_bytes);
    const auto after = std::chrono::steady_clock::now();
    const double lock_ms =
        std::chrono::duration<double, std::milli>(after - before).count();
    if (FAILED(result)) {
      AddErrorEvent(
          HResultCode(result),
          "IDirectSoundBuffer::Unlock",
          std::string(reason) + " unlock failed");
      SetLastError({HResultCode(result), "DirectSound Unlock failed"});
      return false;
    }

    {
      std::lock_guard lock(stats_mutex_);
      stats_.frames_submitted += frames_written;
      stats_.frames_accepted += frames_written;
      ++stats_.callback_count;
      const auto now = std::chrono::steady_clock::now();
      const double interval_ms =
          std::chrono::duration<double, std::milli>(
              now - last_callback_time_).count();
      stats_.last_callback_interval_ms = interval_ms;
      stats_.max_callback_delay_ms =
          std::max(stats_.max_callback_delay_ms, interval_ms);
      CountHighLoadLateCallbackIfNeeded(config_, stats_);
      last_callback_time_ = now;
    }

    if (GetState() == DeviceLifecycleState::kRunningSignal &&
        (force_silence_ ||
         signal_frames_written_.load() >= signal_frame_target_)) {
      if (policy_.keep_warm_after_signal) {
        TransitionTo(DeviceLifecycleState::kRunningSilence,
                     "signal ended; DirectSound PCM silence keep-warm is running");
      } else {
        TransitionTo(DeviceLifecycleState::kHeldOpen,
                     "signal ended; DirectSound buffer remains initialized");
        render_thread_stop_ = true;
      }
    }

    DWORD play_cursor = 0;
    DWORD write_cursor = 0;
    if (secondary_buffer_->GetCurrentPosition(
            &play_cursor,
            &write_cursor) == DS_OK) {
      AddRuntimeEvent(play_cursor, write_cursor, lock_ms, frames_written);
    }
    return true;
  }

  std::uint32_t FillLockedRegions(void* first,
                                  DWORD first_bytes,
                                  void* second,
                                  DWORD second_bytes) {
    const std::uint32_t first_frames =
        first_bytes / wave_format_.Format.nBlockAlign;
    const std::uint32_t second_frames =
        second_bytes / wave_format_.Format.nBlockAlign;
    WriteSignalOrSilence(static_cast<BYTE*>(first), first_frames);
    if (second != nullptr && second_bytes > 0) {
      WriteSignalOrSilence(static_cast<BYTE*>(second), second_frames);
    }
    return first_frames + second_frames;
  }

  void WriteSignalOrSilence(BYTE* output_bytes, std::uint32_t frames) {
    if (output_bytes == nullptr || frames == 0) {
      return;
    }
    const std::size_t total_bytes =
        static_cast<std::size_t>(frames) * wave_format_.Format.nBlockAlign;
    std::memset(output_bytes, 0, total_bytes);

    const std::uint64_t written = signal_frames_written_.load();
    const bool silence_only = force_silence_ || written >= signal_frame_target_;
    const std::uint32_t signal_frames = silence_only
        ? 0
        : static_cast<std::uint32_t>(std::min<std::uint64_t>(
              frames,
              signal_frame_target_ - written));
    if (signal_frames == 0) {
      return;
    }

    PcmSineConfig sine_config;
    sine_config.sample_rate_hz = config_.format.sample_rate_hz;
    sine_config.channel_count = config_.format.channels.channel_count;
    sine_config.frequency_hz = config_.frequency_hz;
    sine_config.amplitude_dbfs = config_.amplitude_dbfs;
    if (config_.left_channel_enabled && !config_.right_channel_enabled) {
      sine_config.channel_assignment = ChannelAssignment::kLeftOnly;
    } else if (!config_.left_channel_enabled && config_.right_channel_enabled) {
      sine_config.channel_assignment = ChannelAssignment::kRightOnly;
    }
    sine_config.invert_right = config_.invert_right_phase;
    sine_config.right_channel_phase_offset_degrees =
        config_.right_channel_phase_offset_degrees;
    const auto samples =
        generator_.GenerateInterleavedFloat32(sine_config, signal_frames);

    const auto bytes = ConvertFloat32InterleavedToPcmBytes(
        samples,
        config_.format.channels.channel_count,
        config_.format);
    if (bytes.empty()) {
      AddErrorEvent(kDirectSoundInvalidArgument,
                    "ConvertFloat32InterleavedToPcmBytes",
                    "failed to convert DirectSound PCM buffer");
      SetLastError({kDirectSoundInvalidArgument,
                    "failed to convert DirectSound PCM buffer"});
      force_silence_ = true;
      return;
    }
    std::memcpy(output_bytes, bytes.data(), bytes.size());
    {
      std::lock_guard lock(stats_mutex_);
      stats_.frames_generated += signal_frames;
    }
    signal_frames_written_ += signal_frames;
  }

  bool RestoreLostBuffer(const char* api) {
    if (!policy_.restores_lost_buffers || secondary_buffer_ == nullptr) {
      return false;
    }
    const HRESULT result = secondary_buffer_->Restore();
    DiagnosticEvent event;
    event.type = DiagnosticEventType::kError;
    event.sequence = NextSequence();
    event.backend = BackendApi::kDirectSound;
    event.device_id = config_.device.stable_id;
    event.message = SUCCEEDED(result)
        ? "DirectSound lost buffer restored conservatively"
        : "DirectSound lost buffer restore failed";
    event.backend_fields["api"] = "IDirectSoundBuffer::Restore";
    event.backend_fields["trigger_api"] = api == nullptr ? "" : api;
    event.backend_fields["result"] = DirectSoundResultSymbol(HResultCode(result));
    AppendEvent(std::move(event));
    {
      std::lock_guard lock(stats_mutex_);
      ++stats_.discontinuity_count;
    }
    return SUCCEEDED(result);
  }

  void RenderLoop() {
    ScopedAudioThreadMmcssRegistration mmcss({
        config_.audio_thread_mmcss_enabled,
        config_.audio_thread_mmcss_task_name,
        config_.audio_thread_mmcss_priority,
    });
    AddThreadSchedulingEvent(
        mmcss.snapshot(),
        "DirectSound render thread MMCSS registration evaluated");
    while (!render_thread_stop_) {
      if (secondary_buffer_ == nullptr) {
        break;
      }

      DWORD status = 0;
      HRESULT result = secondary_buffer_->GetStatus(&status);
      if (FAILED(result)) {
        AddErrorEvent(
            HResultCode(result),
            "IDirectSoundBuffer::GetStatus",
            "failed to query DirectSound secondary buffer status");
        TransitionTo(DeviceLifecycleState::kFaulted,
                     "DirectSound buffer status query failed");
        break;
      }
      if ((status & DSBSTATUS_BUFFERLOST) != 0) {
        if (!RestoreLostBuffer("GetStatus")) {
          TransitionTo(DeviceLifecycleState::kFaulted,
                       "DirectSound lost buffer restore failed");
          break;
        }
        FillBufferRegion(0, buffer_bytes_, "post-restore DirectSound refill");
      }

      DWORD play_cursor = 0;
      DWORD write_cursor = 0;
      result = secondary_buffer_->GetCurrentPosition(&play_cursor, &write_cursor);
      if (FAILED(result)) {
        AddErrorEvent(
            HResultCode(result),
            "IDirectSoundBuffer::GetCurrentPosition",
            "failed to query DirectSound cursors");
        TransitionTo(DeviceLifecycleState::kFaulted,
                     "DirectSound cursor query failed");
        break;
      }

      const std::uint32_t aligned_write =
          write_cursor - (write_cursor % wave_format_.Format.nBlockAlign);
      ApplyHighLoadRenderDelay(config_, GetRealtimeStats().callback_count);
      if (!FillBufferRegion(
              aligned_write,
              chunk_bytes_,
              "DirectSound streaming write")) {
        TransitionTo(DeviceLifecycleState::kFaulted,
                     "DirectSound streaming write failed");
        break;
      }
      std::this_thread::sleep_for(
          std::chrono::milliseconds(policy_.cursor_poll_interval_ms));
    }
    AddThreadSchedulingEvent(
        mmcss.Revert(),
        "DirectSound render thread MMCSS registration reverted");
  }
#endif

  void StopRenderThread() {
    render_thread_stop_ = true;
    if (render_thread_.joinable()) {
      render_thread_.join();
    }
  }

  OperationResult ReleaseAfterDrain() {
    const auto current = GetState();
    if (current != DeviceLifecycleState::kFaulted &&
        current != DeviceLifecycleState::kReleasing &&
        current != DeviceLifecycleState::kReleased) {
      if (!TransitionTo(DeviceLifecycleState::kReleasing,
                        "DirectSound resources releasing after drain")) {
        return OperationResult::Failure(
            kDirectSoundInvalidState,
            GetLastError().message);
      }
    }

    if (policy_.release_cooldown_ms > 0) {
      std::this_thread::sleep_for(
          std::chrono::milliseconds(policy_.release_cooldown_ms));
    }
    ReleaseInterfaces();
    if (GetState() != DeviceLifecycleState::kReleased) {
      if (!TransitionTo(DeviceLifecycleState::kReleased,
                        "DirectSound resources released once")) {
        return OperationResult::Failure(
            kDirectSoundInvalidState,
            GetLastError().message);
      }
    }
    return OperationResult::Success();
  }

  void ReleaseInterfaces() {
#if defined(_WIN32)
    SafeRelease(secondary_buffer_);
    SafeRelease(direct_sound_);
#endif
    buffer_frames_ = 0;
    chunk_frames_ = 0;
    buffer_bytes_ = 0;
    chunk_bytes_ = 0;
  }

  mutable std::mutex state_mutex_;
  mutable std::mutex stats_mutex_;
  mutable std::mutex error_mutex_;
  mutable std::mutex events_mutex_;
  PlaybackConfig config_;
  DirectSoundPcmPolicy policy_;
  RealtimeStats stats_;
  BackendError last_error_;
  std::vector<DiagnosticEvent> events_;
  std::atomic<std::uint64_t> sequence_{0};
  DeviceLifecycleState state_ = DeviceLifecycleState::kDiscovered;
  PcmSineGenerator generator_;
  std::uint64_t signal_frame_target_ = 0;
  std::atomic<std::uint64_t> signal_frames_written_{0};
  std::atomic<bool> force_silence_{false};
  std::atomic<bool> render_thread_stop_{false};
  std::thread render_thread_;
  std::chrono::steady_clock::time_point last_callback_time_ =
      std::chrono::steady_clock::now();
  std::uint32_t buffer_frames_ = 0;
  std::uint32_t chunk_frames_ = 0;
  std::uint32_t buffer_bytes_ = 0;
  std::uint32_t chunk_bytes_ = 0;

#if defined(_WIN32)
  IDirectSound* direct_sound_ = nullptr;
  IDirectSoundBuffer* secondary_buffer_ = nullptr;
  WAVEFORMATEXTENSIBLE wave_format_{};
#endif
};

DirectSoundPcmBackend::DirectSoundPcmBackend()
    : impl_(std::make_unique<Impl>()) {}

DirectSoundPcmBackend::~DirectSoundPcmBackend() = default;

BackendApi DirectSoundPcmBackend::api() const {
  return impl_->Api();
}

DeviceList DirectSoundPcmBackend::enumerateDevices() {
  return impl_->EnumerateDevices();
}

FormatProbeResult DirectSoundPcmBackend::probeFormats(const DeviceInfo& device) {
  return impl_->ProbeFormats(device);
}

OperationResult DirectSoundPcmBackend::initialize(const PlaybackConfig& config) {
  return impl_->Initialize(config);
}

OperationResult DirectSoundPcmBackend::start() {
  return impl_->Start();
}

OperationResult DirectSoundPcmBackend::stop() {
  return impl_->Stop();
}

OperationResult DirectSoundPcmBackend::reset() {
  return impl_->Reset();
}

RealtimeStats DirectSoundPcmBackend::getRealtimeStats() const {
  return impl_->GetRealtimeStats();
}

BackendError DirectSoundPcmBackend::getLastError() const {
  return impl_->GetLastError();
}

OperationResult DirectSoundPcmBackend::shutdown() {
  return impl_->Shutdown();
}

DeviceLifecycleState DirectSoundPcmBackend::lifecycle_state() const {
  return impl_->GetState();
}

std::vector<DiagnosticEvent> DirectSoundPcmBackend::diagnostic_events() const {
  return impl_->GetEvents();
}

}  // namespace aptt
