//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2020
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once

#include "telegram-bot-api/Client.h"
#include "telegram-bot-api/Query.h"
#include "telegram-bot-api/Stats.h"

#include "td/actor/actor.h"
#include "td/actor/PromiseFuture.h"

#include "td/utils/buffer.h"
#include "td/utils/common.h"
#include "td/utils/Container.h"
#include "td/utils/FloodControlFast.h"
#include "td/utils/Slice.h"

#include <memory>
#include <unordered_map>
#include <utility>

namespace telegram_bot_api {

struct ClientParameters;
struct SharedData;

class ClientManager final : public td::Actor {
 public:
  struct TokenRange {
    td::uint64 rem;
    td::uint64 mod;
    bool operator()(td::uint64 x) {
      return x % mod == rem;
    }
  };
  ClientManager(std::shared_ptr<const ClientParameters> parameters, TokenRange token_range)
      : parameters_(std::move(parameters)), token_range_(token_range) {
  }

  void send(PromisedQueryPtr query);
  void user_login(PromisedQueryPtr query);

  bool check_flood_limits(PromisedQueryPtr &query, bool is_user_login=false);

  void get_stats(td::PromiseActor<td::BufferSlice> promise, td::vector<std::pair<td::string, td::string>> args);

  void close(td::Promise<td::Unit> &&promise);

 private:
  class ClientInfo {
   public:
    BotStatActor stat_;
    td::string token_;
    td::ActorOwn<Client> client_;
  };
  td::Container<ClientInfo> clients_;
  BotStatActor stat_{td::ActorId<BotStatActor>()};

  std::shared_ptr<const ClientParameters> parameters_;
  TokenRange token_range_;

  std::unordered_map<td::string, td::uint64> token_to_id_;
  std::unordered_map<td::string, td::FloodControlFast> flood_controls_;

  bool close_flag_ = false;
  td::vector<td::Promise<td::Unit>> close_promises_;

  static td::int64 get_tqueue_id(td::int64 user_id, bool is_test_dc);

  static PromisedQueryPtr get_webhook_restore_query(td::Slice token, bool is_user, td::Slice webhook_info,
                                                    std::shared_ptr<SharedData> shared_data);

  void start_up() override;
  void hangup_shared() override;
  void close_db();
  void finish_close();
};

}  // namespace telegram_bot_api
