// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#pragma once

#include <fmt/format.h>
#include <rapidjson/document.h>
#include <simdjson.h> // IWYU pragma: keep

#include <sstream>
#include <string>
#include <utility>
#include <vector>

#include "common/status.h"

namespace simdjson {
namespace fallback {
namespace ondemand {
class object;
class value;
} // namespace ondemand
} // namespace fallback
} // namespace simdjson

namespace doris {

enum JsonFunctionType {
    JSON_FUN_INT = 0,
    JSON_FUN_DOUBLE,
    JSON_FUN_STRING,

    JSON_FUN_UNKNOWN //The last
};

struct JsonPath {
    std::string key; // key of a json object
    int idx;         // array index of a json array, -1 means not set, -2 means *
    bool is_valid;   // true if the path is successfully parsed

    JsonPath(const std::string& key_, int idx_, bool is_valid_)
            : key(key_), idx(idx_), is_valid(is_valid_) {}

    JsonPath(std::string&& key_, int idx_, bool is_valid_)
            : key(std::move(key_)), idx(idx_), is_valid(is_valid_) {}

    std::string to_string() const {
        std::stringstream ss;
        if (!is_valid) {
            return "INVALID";
        }
        if (!key.empty()) {
            ss << key;
        }
        if (idx == -2) {
            ss << "[*]";
        } else if (idx > -1) {
            ss << "[" << idx << "]";
        }
        return ss.str();
    }

    std::string debug_string() const {
        return fmt::format("key:{}, idx:{}, valid:{}", key, idx, is_valid);
    }
};

class JsonFunctions {
public:
    /**
     * The `document` parameter must be has parsed.
     * return Value Is Array object
     * wrap_explicitly is set to true when the returned Array is wrapped actively.
     */
    static rapidjson::Value* get_json_array_from_parsed_json(
            const std::vector<JsonPath>& parsed_paths, rapidjson::Value* document,
            rapidjson::Document::AllocatorType& mem_allocator, bool* wrap_explicitly);

    // this is only for test, it will parse the json path inside,
    // so that we can easily pass a json path as string.
    static rapidjson::Value* get_json_array_from_parsed_json(
            const std::string& jsonpath, rapidjson::Value* document,
            rapidjson::Document::AllocatorType& mem_allocator, bool* wrap_explicitly);

    static rapidjson::Value* get_json_object_from_parsed_json(
            const std::vector<JsonPath>& parsed_paths, rapidjson::Value* document,
            rapidjson::Document::AllocatorType& mem_allocator);

    static void parse_json_paths(const std::string& path_strings,
                                 std::vector<JsonPath>* parsed_paths);
    // extract_from_object extracts value from object according to the json path.
    // Now, we do not support complete functions of json path.
    // Eg. city[*].id is not supported in this function
    static Status extract_from_object(simdjson::ondemand::object& obj,
                                      const std::vector<JsonPath>& jsonpath,
                                      simdjson::ondemand::value* value) noexcept;
    // src:    {"a" : "b" {"c" : 1}, "e" : 123}
    // dst:    {"a" : "b" {"d" : 1}}
    // merged: {"a" : "b" : {"c" : 1, "d" : 1}, "e" : 123}
    static void merge_objects(rapidjson::Value& dst_object, rapidjson::Value& src_object,
                              rapidjson::Document::AllocatorType& allocator);

    static std::string print_json_value(const rapidjson::Value& value);

    static bool is_root_path(const std::vector<JsonPath>& json_path);

private:
    static rapidjson::Value* match_value(const std::vector<JsonPath>& parsed_paths,
                                         rapidjson::Value* document,
                                         rapidjson::Document::AllocatorType& mem_allocator,
                                         bool is_insert_null = false);
    static void get_parsed_paths(const std::vector<std::string>& path_exprs,
                                 std::vector<JsonPath>* parsed_paths);
};
} // namespace doris
