#include "backends/wasapi_error.h"

#include <cstdint>
#include <sstream>

namespace aptt {
namespace {

constexpr std::uint32_t kAudclntDeviceInvalidated = 0x88890004u;
constexpr std::uint32_t kAudclntUnsupportedFormat = 0x88890008u;
constexpr std::uint32_t kAudclntDeviceInUse = 0x8889000Au;
constexpr std::uint32_t kAudclntExclusiveModeNotAllowed = 0x8889000Eu;
constexpr std::uint32_t kAudclntEndpointCreateFailed = 0x8889000Fu;
constexpr std::uint32_t kAudclntServiceNotRunning = 0x88890010u;
constexpr std::uint32_t kAudclntCpuUsageExceeded = 0x88890017u;
constexpr std::uint32_t kAudclntBufferSizeNotAligned = 0x88890019u;
constexpr std::uint32_t kAudclntResourcesInvalidated = 0x88890026u;

std::uint32_t CodeBits(int code) {
  return static_cast<std::uint32_t>(code);
}

const char* WasapiAudioClientErrorAction(int code) {
  switch (CodeBits(code)) {
    case kAudclntDeviceInUse:
      return "selected WASAPI endpoint is already in use; close other apps or drivers using the endpoint, especially exclusive-mode players, DAWs, measurement tools, browsers, or vendor panels, then retry the same profile";
    case kAudclntUnsupportedFormat:
      return "requested format was rejected; run the selected-endpoint format probe and choose an exact supported IsFormatSupported row";
    case kAudclntExclusiveModeNotAllowed:
      return "exclusive mode is not allowed for this endpoint; enable exclusive-mode permission in Windows sound settings or use WASAPI shared";
    case kAudclntBufferSizeNotAligned:
      return "exclusive buffer duration is not aligned to the device period; retry with the device-reported aligned period";
    case kAudclntDeviceInvalidated:
      return "endpoint was invalidated; avoid rapid reacquire, wait for cooldown, then refresh the selected endpoint";
    case kAudclntResourcesInvalidated:
      return "audio resources were invalidated; stop the run, wait for cooldown, and refresh the selected endpoint";
    case kAudclntServiceNotRunning:
      return "Windows Audio service is not running or became unavailable";
    case kAudclntEndpointCreateFailed:
      return "WASAPI could not create the endpoint stream for this profile";
    case kAudclntCpuUsageExceeded:
      return "Windows Audio rejected the stream due to CPU usage constraints";
    default:
      return "unexpected WASAPI HRESULT; inspect nearby lifecycle and format probe records";
  }
}

}  // namespace

const char* WasapiAudioClientErrorSymbol(int code) {
  switch (CodeBits(code)) {
    case kAudclntDeviceInvalidated:
      return "AUDCLNT_E_DEVICE_INVALIDATED";
    case kAudclntUnsupportedFormat:
      return "AUDCLNT_E_UNSUPPORTED_FORMAT";
    case kAudclntDeviceInUse:
      return "AUDCLNT_E_DEVICE_IN_USE";
    case kAudclntExclusiveModeNotAllowed:
      return "AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED";
    case kAudclntEndpointCreateFailed:
      return "AUDCLNT_E_ENDPOINT_CREATE_FAILED";
    case kAudclntServiceNotRunning:
      return "AUDCLNT_E_SERVICE_NOT_RUNNING";
    case kAudclntCpuUsageExceeded:
      return "AUDCLNT_E_CPUUSAGE_EXCEEDED";
    case kAudclntBufferSizeNotAligned:
      return "AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED";
    case kAudclntResourcesInvalidated:
      return "AUDCLNT_E_RESOURCES_INVALIDATED";
    default:
      return "HRESULT";
  }
}

std::string DescribeWasapiAudioClientError(int code,
                                           std::string_view api,
                                           std::string_view context) {
  std::ostringstream message;
  message << api << " failed (" << WasapiAudioClientErrorSymbol(code)
          << ", code=" << code << "): " << context << "; "
          << WasapiAudioClientErrorAction(code);
  return message.str();
}

}  // namespace aptt
