#pragma once

#include <Poco/Nullable.h>
#include <Poco/Data/Session.h>

#include <mapreduce/yt/interface/client.h>

#include "host_info_map.h"
#include "mirrors_resolver.h"

namespace NWebmaster {

class THostProcessor {
    static const ui32 insert_pack = 256;

public:
    THostProcessor(const std::string &yt_cluster, const std::string &yt_root, const std::string &input_table_name, TMirrorResolver::Ptr mirrorResolver);

    static bool endsWith(const std::string &str, const std::string &ending);
    static bool isSubdomain(const std::string &_subdomain, const std::string &_domain);
    static bool isHTTPS(const std::string &hostname);
    static bool isWWW(const std::string &hostname, bool https = false);
    static std::string alterWWW(const std::string &hostname);
    static std::string unWWW(const std::string &hostname);

    /** Round number by dropping less significant part of number
      *
      */
    static ui32 round_limit_trunc(double limit);

    /** Round helper method
      *
      */
    static ui32 round_to_radix(ui32 n, ui32 radix);

    /** Round number to grid:
      *         0..100    => x10
      *       100..5000   => x100
      *      5000..10000  => x500
      *     10000..50000  => x1000
      */
    static ui32 round_limit(double limit);

    static Poco::Nullable<double> get_config_params(Poco::Data::Session &sess, const std::string &name);

    /** Loads all config about ranks, grid. Loads verified hosts
      * from WebMaster DB [host_id, name, limit, (main)user_id].
      *
      */
    void define_input_params(THostInfoMap &hosts_info_map, const TUserInfoMap &user_info_map);

    /** Load users from XMLSearch DB'ses [user_id, limit].
      *
      */
    static void define_users(TUserInfoMap &user_info_map);

    /** Load ranks from Antispam YT table (usually: xml_discrete*.*).
      * Process each loaded host with "process_rank".
      *
      */
    double load_ranks(THostInfoMap &hosts_info_map, const TUserInfoMap &user_info_map);
    void load_rank_owners_mirrors();


    bool find_host(THostInfoMap &hosts_info_map, const std::string &owner, THostInfoMap::iterator &iter, bool force_find_main_user = false);

    /** Process lines from Antispam file with ranks. If AntiSpam rank == 0,
      * or host not found in WebMaster HOST_DBs - skip it.
      *
      */
    void process_rank(const std::string &owner,
                           ui32 rank,
                           THostInfoMap &hosts_info_map,
                           const TUserInfoMap &user_info_map,
                           double &sum_limit);

    /** Recalculates available limit and places to WebMaster USER_DB if it was not defined
      *
      */
    void define_limit1_rank(double sum_limit);

    /** Calculates hosts limits
      * @return Overall charged limit
      */
    ui32 define_limits(THostInfoMap &host_info_map, TUserInfoMap &user_info_map, double sum_limit);

    static void construct_wmc_query(std::string_view table_name, std::stringstream &query, ui32 &cur_insert_num, const THostInfo &hi);
    static void construct_wmc_query_no_check(std::string_view table_name, std::stringstream &query, ui32 &cur_insert_num, const THostInfo &hi);
    static void construct_xml_query(std::stringstream &query, ui32 &cur_insert_num, const TUserIdMap::value_type &user);
    static void export_wmc_limits_to_yt(NYT::IClientBasePtr client, const THostInfoMap &hosts_info_map, const std::string &root);
    static void export_xml_limits_to_yt(NYT::IClientBasePtr client, const TUserInfoMap &user_info_map, const std::string &root);
    static void limits_to_wmc_db(const THostInfoMap &hosts_info_map);
    static void limits_to_xml_db(const TUserInfoMap &user_info_map);
    static void exec_query(Poco::Data::Session &sess, const std::stringstream &query);
    static void log_exec_query(Poco::Data::Session &sess, const std::stringstream &query);
    static void log_exec_wmc_query(const std::stringstream &query);
    static void log_exec_xml_query(size_t db_num, const std::stringstream &query);
    static void thr_xml_db(size_t db_num, const TUserIdMap &users);

private:
    ui32 xml_l_min;
    ui32 xml_l_max;
    double limit1_rank;
    bool first_load;
    const std::string yt_cluster;
    const std::string yt_root;
    const std::string input_table_name;
    static const ui32 min_rank = 10;
    static const ui32 max_rank = 50000;
    static const ui32 rank_step = 10;
    std::map<ui32, double> rank_to_norm;
    TMirrorResolver::Ptr MirrorResolver;
};

} //namespace NWebmaster
