namespace samples::http_cache {
 
struct KeyLang {
  std::string key;
  std::string language;
};
 
struct KeyLangEq {
  bool operator()(const KeyLang& x, const KeyLang& y) const noexcept;
};
 
struct KeyLangHash {
  bool operator()(const KeyLang& x) const noexcept;
};
 
using KeyLangToTranslation =
    std::unordered_map<KeyLang, std::string, KeyLangHash, KeyLangEq>;
 
}  
 
namespace samples::http_cache {
 
bool KeyLangEq::operator()(const KeyLang& x, const KeyLang& y) const noexcept {
  return x.key == y.key && x.language == y.language;
}
 
bool KeyLangHash::operator()(const KeyLang& x) const noexcept {
  std::string data;
  data.append(x.key);
  data.append(x.language);
  return std::hash<std::string>{}(data);
}
 
}  
 
namespace samples::http_cache {
 
class HttpCachedTranslations final
 public:
  static constexpr std::string_view kName = "cache-http-translations";
 
  ~HttpCachedTranslations() override;
 
  void Update(
      [[maybe_unused]] const std::chrono::system_clock::time_point& last_update,
      [[maybe_unused]] const std::chrono::system_clock::time_point& now,
 
 
 private:
  const std::string translations_url_;
  std::string last_update_remote_;
 
 
  void MergeAndSetData(KeyLangToTranslation&& content,
};
 
}  
 
namespace samples::http_cache {
 
HttpCachedTranslations::HttpCachedTranslations(
    : CachingComponentBase(config, context),
      http_client_(
          context.FindComponent<
components::HttpClient>().GetHttpClient()),
 
      translations_url_(config[
"translations-url"].As<
std::string>()) {
 
  CacheUpdateTrait::StartPeriodicUpdates();
}
 
HttpCachedTranslations::~HttpCachedTranslations() {
  CacheUpdateTrait::StopPeriodicUpdates();
}
 
void HttpCachedTranslations::Update(
    [[maybe_unused]] const std::chrono::system_clock::time_point& last_update,
    [[maybe_unused]] const std::chrono::system_clock::time_point& now,
  switch (type) {
      json = GetAllData();
      break;
      json = GetUpdatedData();
      break;
    default:
  }
 
  if (json.IsEmpty()) {
    return;
  }
 
  KeyLangToTranslation content;
    const auto snapshot = Get();  
    content = *snapshot;          
  }
 
  MergeAndSetData(std::move(content), json, stats_scope);
}
 
  auto response = http_client_.CreateRequest()
                      .get(translations_url_)  
                      .retry(2)                
                      .timeout(std::chrono::milliseconds{500})
                      .perform();  
  response->raise_for_status();
}
 
  const auto url =
      http::MakeUrl(translations_url_, {{
"last_update", last_update_remote_}});
 
  auto response = http_client_.CreateRequest()
                      .get(url)
                      .retry(2)
                      .timeout(std::chrono::milliseconds{500})
                      .perform();
  response->raise_for_status();
}
 
void HttpCachedTranslations::MergeAndSetData(
  for (const auto& [key, value] : Items(json["content"])) {
    for (const auto& [lang, text] : Items(value)) {
      content.insert_or_assign(KeyLang{key, lang}, text.As<std::string>());
    }
  }
 
  auto update_time = json["update_time"].As<std::string>();
 
  const auto size = content.size();
  Set(std::move(content));
  last_update_remote_ = std::move(update_time);
}
 
 public:
  static constexpr std::string_view kName = "handler-greet-user";
 
      : HttpHandlerBase(config, context),
        cache_(context.FindComponent<HttpCachedTranslations>()) {}
 
    const auto cache_snapshot = cache_.Get();
 
    using samples::http_cache::KeyLang;
    const auto& hello = cache_snapshot->at(KeyLang{"hello", "ru"});
    const auto& welcome = cache_snapshot->at(KeyLang{"welcome", "ru"});
    return fmt::format(
"{}, {}! {}", hello, request.
GetArg(
"username"),
 
                       welcome);
  }
 
 private:
  samples::http_cache::HttpCachedTranslations& cache_;
};
 
type: object
description: HTTP caching sample component
additionalProperties: false
properties:
    translations-url:
        type: string
        description: some other microservice listens on this URL
)");
}
 
}  
 
int main(int argc, char* argv[]) {
  const auto component_list =
          .
Append<samples::http_cache::HttpCachedTranslations>()
 
          .Append<samples::http_cache::GreetUser>()
          .Append<server::handlers::TestsControl>()
          .Append<components::HttpClient>();
}