#pragma once

#include <maps/libs/enum_io/include/enum_io.h>

#include <map>
#include <pqxx/pqxx>

namespace maps::wiki::query_builder {

enum class Relation {
    Ilike,
    Less,
    LessOrEqual,
    Like,
    Greater,
    GreaterOrEqual,
    Equal,
    NotEqual,
    Intersects
};
DECLARE_ENUM_IO(Relation);

enum class Quote {
    No,
    Yes,
    Raw
};

struct QuotedValue {
    std::string value;
    Quote needQuote;

    std::string quote(const pqxx::transaction_base& txn) const;
    auto introspect() const { return std::tie(value, needQuote); }
};

enum class JsonbType {
    Text,
    BigInt
};
DECLARE_ENUM_IO(JsonbType);

struct JsonbEntry {
    std::vector<std::string> path;
    std::string value;
    JsonbType type;
};

class ModifyData {
public:
    ModifyData() = default;
    ModifyData(const ModifyData&) = default;
    ModifyData& operator=(const ModifyData&) = default;
    ModifyData(ModifyData&&) = default;
    ModifyData& operator=(ModifyData&&) = default;


    void append(std::string key, std::string value);
    void appendQuoted(std::string key, std::string value);
    void appendRawQuoted(std::string key, std::string value);
    void appendJsonbEntry(std::string key, JsonbEntry value);
    void setReturning(std::vector<std::string> columns);

    bool empty() const { return keyValues_.empty() && jsonbEntries_.empty(); }
    const auto& keyValues() const { return keyValues_; }
    const auto& jsonbEntries() const { return jsonbEntries_; }
    const auto& returning() const { return returningColumns_; }

    auto introspect() const { return keyValues_; }

private:
    void appendNoDuplicate(std::string key, QuotedValue quotedValue);

    std::map<std::string, QuotedValue> keyValues_;
    std::map<std::string, JsonbEntry> jsonbEntries_;
    std::vector<std::string> returningColumns_;
};

std::string joinJsonbPath(
    const std::string& column,
    const std::vector<std::string>& path);

std::string makeJsonbSetExpression(
    const pqxx::transaction_base& txn,
    const std::string& column,
    const JsonbEntry& value);

} // namespace maps::wiki::query_builder
