#pragma once
#include "curl/multi.h"
#include "uv.h"
#include <chrono>
#include <functional>
#include <map>
#include <string>

namespace detail {
template <class... Fs>
struct overload;

template <class F>
struct overload<F> : public F {
  explicit overload(F f) : F(f) {
  }
};
template <class F, class... Fs>
struct overload<F, Fs...>
    : public overload<F>
    , public overload<Fs...> {
  overload(F f, Fs... fs) : overload<F>(f), overload<Fs...>(fs...) {
  }
  using overload<F>::operator();
  using overload<Fs...>::operator();
};
}  // namespace detail

template <class... F>
auto overloaded(F... f) {
  return detail::overload<F...>(f...);
}


enum class CommandLineParamError {
  NoApiCreds
};

struct ApiCreds {
  int id;
  std::string hash;
  std::string botToken;
};

struct CommandLineParams {
  ApiCreds apiCreds;
  std::string botToken;
};

struct TelegramClient;

struct active_request {
  std::vector<char> receivedData;
  std::function<void(active_request&)> doneCallback;

  active_request(std::function<void(active_request&)> doneCallback): doneCallback(doneCallback) {}
};

struct pending_inline_query {
  std::string text;
  std::chrono::time_point<std::chrono::steady_clock> ttl;
};

struct context {
  TelegramClient *tg;
  ApiCreds apiCreds;
  CURLM *curl;
  uv_timer_t curlTimer;
  std::map<CURL*, active_request> requests;
  std::map<uint64_t, pending_inline_query> inlineQueries;
};

size_t curl_receive_cb(char *ptr, size_t size, size_t nmemb, CURL *ctx);