#pragma once

#include <map>
#include <set>
#include <string>


namespace maps {
namespace wiki {
namespace ymapsdf_splitter {
namespace sql {

class Join {
private:
    enum class Type {Inner, Left};

public:
    Join(
        const std::string& joinTable,
        const std::string& fromTableColumn,
        const std::string& joinTableColumn = "");

    Join& left();

    Join& as(const std::string& as);
    const std::string& as() const;

    // By default all joined tables are used in `WHERE join_table.isocode IN ...`
    // conditions, however sometimes they must not.
    Join& notUseInWhere();
    bool useInWhere() const;

    std::string operator () (
        const std::string& fromSchema,
        const std::string& fromTable) const;

private:
    std::string joinTable_;
    std::string fromTableColumn_;
    std::string joinTableColumn_;
    std::string as_;
    Type type_ = Type::Inner;
    bool useInWhere_ = true;

    std::string onClause(const std::string& fromTable) const;

    std::string usingClause() const;
};


using Joins = std::multimap<std::string, Join>;            // table name -> join
using Tables = std::set<std::string>;


std::string query(
    const std::string& connStr,
    const std::string& fromSchema,
    const std::string& toSchema,
    const std::string& table,
    const Joins& joins,
    const std::string& isocodes);

Tables getTables(const Joins& joins);

} // namespace sql
} // namespace ymapsdf_splitter
} // namespace wiki
} // namespace maps
