// Copyright (c) 2023
// All rights reserved.
#pragma once

#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <string>
#include <unordered_set>

#include "rapidjson/document.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"

namespace xxx {

namespace test {
#define DEFAULT_STR ("None")

inline std::string SerializeJsonToString(const rapidjson::Document& json) {
  rapidjson::StringBuffer buffer;
  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
  json.Accept(writer);
  return std::string(buffer.GetString(), buffer.GetSize());
}

inline int SafeStoi(const std::string& str, int default_value) {
  try {
    if (str.size() <= 0) {
      return default_value;
    } else {
      return std::stoi(str);
    }
  } catch (const std::invalid_argument& e) {
    TRPC_FMT_ERROR("Invalid argument: {}, str:{}", e.what(), str);
  } catch (const std::out_of_range& e) {
    TRPC_FMT_ERROR("Out of range: {}, str:{}", e.what(), str);
  }
  return default_value;
}

inline long long SafeStoll(const std::string& str, long long default_value) {
  try {
    if (str.size() <= 0) {
      return default_value;
    } else {
      return std::stoll(str);
    }
  } catch (const std::invalid_argument& e) {
    TRPC_FMT_ERROR("Invalid argument: {}, str:{}", e.what(), str);
  } catch (const std::out_of_range& e) {
    TRPC_FMT_ERROR("Out of range: {}, str:{}", e.what(), str);
  }
  return default_value;
}

inline std::string SafeSubstr(
    const std::string& str, size_t pos, size_t len, const std::string& default_value) {
  if (len <= 0 || len > str.size()) {
    TRPC_FMT_ERROR("str:{}, pos:{}, len:{}, Out of range", str, pos, len);
    return default_value;
  } else {
    return str.substr(pos, len);
  }
  return default_value;
}

inline std::string SafeSubstr(
    const std::string& str, size_t pos, const std::string& default_value) {
  try {
    return str.substr(pos);
  } catch (const std::out_of_range& e) {
    TRPC_FMT_ERROR("Out of range: {}", e.what());
  }
  return default_value;
}

inline std::string GetFormattedDate(int offset) {
  auto now = std::chrono::system_clock::now();
  std::time_t time = std::chrono::system_clock::to_time_t(now - std::chrono::hours(24 * offset));
  std::tm tm = *std::localtime(&time);
  std::ostringstream oss;
  oss << std::put_time(&tm, "%Y%m%d");
  return oss.str();
}

inline std::string GetFormattedDateByMsTimeStamp(uint64_t ms_time) {
  std::time_t time = static_cast<std::time_t>(ms_time / 1000);
  std::tm tm = *std::localtime(&time);
  std::ostringstream oss;
  oss << std::put_time(&tm, "%Y%m%d");
  return oss.str();
}


// 占位类型
struct void_type {};
template <typename Func, typename... Args>
auto measure_time(Func func, Args... args) -> typename std::conditional<std::is_void<typename std::result_of<Func(Args...)>::type>::value, void_type, typename std::result_of<Func(Args...)>::type>::type {
    auto start_time = std::chrono::high_resolution_clock::now();
    func(args...);  // 直接调用函数,不存储结果
    auto end_time = std::chrono::high_resolution_clock::now();
    auto elapsed_time =
            std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time).count();
    std::cout << "Function took " << elapsed_time << " microseconds to execute." << std::endl;
}

// set1 - set2
template <typename T>
std::unordered_set<T> SetDifference(
    const std::unordered_set<T>& set1, const std::unordered_set<T>& set2) {
  if (set1.empty() || set2.empty()) {
    return set1;
  }
  std::unordered_set<T> result = set1;
  for (const auto& elem : set2) {
    auto it = result.find(elem);
    if (it != result.end()) {
      result.erase(it);
    }
  }
  return result;
}

// 判断是否是整点
inline bool IsOnTheHour(time_t timestamp) {
  tm* timeinfo = localtime(&timestamp);
  return timeinfo->tm_min == 0 && timeinfo->tm_sec == 0;
}

}  // namespace test
}  // namespace xxxx