/*
{{copyright}} 
*/

/*
{{version}} 
*/

/*
{{license}} 
*/

#pragma once

#include <boost/uuid/uuid.hpp>                // Pour boost::uuids::uuid
#include <boost/uuid/uuid_generators.hpp>     // Pour boost::uuids::random_generator
#include <boost/uuid/uuid_io.hpp>             // Pour boost::uuids::to_string
#include <format>
#include <string>

namespace sdi_toolBox::generic
{
//--------------------------------------------------------------
class UuidGenerator
{
  public:
  static std::string uuid_v4();                            // Generate a random UUID v4 string
  static std::string uniqid(bool moreEntropy = false);     // Generate a unique identifier string (as in PHP)

  protected:
  UuidGenerator()                                     = default;     // Default constructor
  ~UuidGenerator()                                    = default;     // Default destructor
  UuidGenerator(const UuidGenerator &)                = default;     // Copy constructor
  UuidGenerator(UuidGenerator &&) noexcept            = default;     // Move constructor
  UuidGenerator &operator=(const UuidGenerator &)     = default;     // Copy assignment operator
  UuidGenerator &operator=(UuidGenerator &&) noexcept = default;     // Move assignment operator
};
//--------------------------------------------------------------
/* Generate a random UUID v4 string */
inline std::string UuidGenerator::uuid_v4()
{
  boost::uuids::random_generator gen;           // Create a random UUID generator
  boost::uuids::uuid             u = gen();     // Generate a random UUID
  return boost::uuids::to_string(u);            // Convert the UUID to a string and return it
}
//--------------------------------------------------------------
/* Generate a unique identifier string (as in PHP) */
inline std::string UuidGenerator::uniqid(const bool moreEntropy)
{
  const auto now            = std::chrono::high_resolution_clock::now();     // Get current time point
  const auto epoch          = now.time_since_epoch();                        // Get duration since epoch
  const auto us_since_epoch = std::chrono::duration_cast<std::chrono::microseconds>(epoch).count();

  // Format the time part into a hexadecimal string
  const auto time_part = us_since_epoch / 16;

  std::string result = std::format("{0:x}", time_part);

  // PHP's uniqid pads the result to 13 characters if needed. We replicate the core logic.
  // If the time part is shorter than 13 characters (highly unlikely today), it should be padded.
  if (result.length() < 13)
    result.insert(0, 13 - result.length(), '0');

  // Add more entropy if requested (similar to PHP's second argument = true)
  if (moreEntropy)
  {
    // Generate 5 bytes of random data (10 characters hex)
    static std::random_device rd;
    static std::mt19937       generator(rd());
    unsigned int              rand_val = generator();     // Generate a random 32-bit number and use a portion of a second random number

    // Append the random data in hexadecimal format
    result = result + std::format(".{0:08x}", rand_val);
  }

  return result;
}
//--------------------------------------------------------------
}     // namespace sdi_toolBox::generic
