#include <maps/wikimap/mapspro/libs/dbutils/include/parser.h>
#include <maps/libs/common/include/exception.h>

#include <sstream>

namespace maps::wiki::dbutils {

std::vector<std::string>
parseCSV(const std::string& csvString, char delimiter, char escape)
{
    std::vector<std::string> ret;
    bool insideQuotes = false;
    std::stringstream phrase;
    for (size_t i = 0; i < csvString.length(); ++i) {
        if (csvString[i] == '"') {
            insideQuotes = !insideQuotes;
        } else if(csvString[i] == escape) {
            i++;
            REQUIRE(csvString.length() != i,
                "Unexpected escape character at end: " << csvString);
            phrase << csvString[i];
        } else if (!insideQuotes && csvString[i] == delimiter) {
            ret.push_back(phrase.str());
            phrase.clear();
            phrase.str("");
        } else if (!insideQuotes && (csvString[i] == ' ' || csvString[i] == '\t')) {
            // Skip spaces outside quoted area
        } else {
            phrase << csvString[i];
        }
    }
    auto last = phrase.str();
    if (!last.empty()) {
        ret.push_back(last);
    }
    return ret;
}

std::vector<std::string>
parsePGArray(const std::string& postgresArray)
{
    if (postgresArray.empty() || postgresArray == "{}") {
        return {};
    }
    auto parts = parseCSV(postgresArray, ',', '\\');
    if (!parts.empty()) {
        // Remove { and } symbols
        ASSERT(!parts.back().empty());
        parts.back().resize(parts.back().length() - 1);
        parts.front().erase(0, 1);
    }
    return parts;
}

std::map<std::string, std::string>
parsePGHstore(const std::string& hstoreArray)
{
    if (hstoreArray.empty()) {
        return {};
    }

    auto parts = parsePGArray(hstoreArray);
    if (parts.empty()) {
        return {};
    }
    REQUIRE(!(parts.size() & 1),
        "Odd number of parts in hstoreArray: " << hstoreArray);

    std::map<std::string, std::string> ret;
    for (size_t i = 0; i < parts.size(); i += 2) {
        ret.emplace(parts[i], parts[i + 1]);
    }
    return ret;
}

} // namespace maps::wiki::dbutils
