#ifndef MLIB_ERROR_PRIVATE_H
#define MLIB_ERROR_PRIVATE_H

#include "./user-check.h"

#include "./str.h"

#ifdef _WIN32
#include "./windows-lean.h"
#else
#include <errno.h>
#endif

/**
 * @brief Obtain a string containing an error message corresponding to an error
 * code from the host platform.
 *
 * @param errn An error code for the system. (e.g. GetLastError() on Windows)
 * @return mstr A new string containing the resulting error. Must be freed with
 * @ref mstr_free().
 */
static inline mstr
merror_system_error_string (int errn)
{
#ifdef _WIN32
   wchar_t *wbuffer = NULL;
   DWORD slen = FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER |
                                   FORMAT_MESSAGE_FROM_SYSTEM |
                                   FORMAT_MESSAGE_IGNORE_INSERTS,
                                NULL,
                                (DWORD) errn,
                                0,
                                (LPWSTR) &wbuffer,
                                0,
                                NULL);
   if (slen == 0) {
      return mstr_copy_cstr (
         "[Error while getting error string from FormatMessageW()]");
   }
   mstr_narrow_result narrow = mstr_win32_narrow (wbuffer);
   LocalFree (wbuffer);
   assert (narrow.error == 0);
   // Messages from FormatMessage contain an additional CR+LF
   if (mstr_ends_with (narrow.string.view, mstrv_lit ("\r\n"))) {
      mstr_inplace_remove_suffix (&narrow.string, 2);
   }
   return narrow.string;
#else
   errno = 0;
   char *const str = strerror (errn);
   if (errno) {
      return mstr_copy_cstr (
         "[Error while getting error string from strerror()]");
   }
   return mstr_copy_cstr (str);
#endif
}

#endif // MLIB_ERROR_PRIVATE_H