#include <iostream>
#include <utility>
#include "Json.h"
#include <fstream>
#include <sstream>
std::function<void(const char*, const std::string&, const char*, int)> Json::handle_error = [](const char* function_name, const std::string& reason, const char* file, int line) {
    std::ostringstream oss;
    oss << "Json::" << function_name << " 原因：" << reason  << std::endl;
    oss << "位置：" << file << ":" << line << std::endl;
    //throw std::runtime_error(oss.str().c_str());
    std::cout << oss.str();
    exit(-1);
};

#define HANDLE_ERROR(reason) Json::handle_error(__func__, reason, __FILE__, __LINE__);
void skip_whitespace(std::string& s, size_t& i);
std::string parse_string(std::string& s, size_t& i);
std::string parse_number(std::string& s, size_t& i);
std::optional<Json> parse_object(std::string& s, size_t& i);
std::optional<Json> parse_array(std::string& s, size_t& i);

std::ostream& operator<<(std::ostream& os, const Json& obj) {
    os << const_cast<Json&>(obj).to_json_string();
    return os;
}

Json::operator std::string() const {
    return const_cast<Json*>(this)->to_json_string();
}

std::string Json::get_string(const std::string& key) const {
    const Json* that = get(key);
    if (!that) {
        HANDLE_ERROR(key + " not found! " + to_json_string())
        return "";
    }
    return that->val;
}

bool Json::bool_val() const {
    if (val != "true" && val != "false") {
        HANDLE_ERROR("Invalid bool argument: " + val)
    }
    return (val == "true");
}

const std::string& Json::get_inside_string(const std::string& key) const {
    const Json* that = get(key);
    if (!that) {
        HANDLE_ERROR(key + " not found!")
        return that->val;
    }
    return that->val;
}

Json::Json(std::string key, const char* val) : key(std::move(key)), val(std::string(val)), valueType(String) {
}

Json::Json(std::string key, std::string val) : key(std::move(key)), val(std::move(val)), valueType(String) {
}

Json::Json(std::string key, bool val) : key(std::move(key)), val(val ? "true" : "false"), valueType(Bool) {
}

Json::Json(std::string key, const Json& children) :
    key(std::move(key)), val(children.val), valueType(children.valueType), children(children.children) {}


void Json::append_list(const std::vector<Json>& arr) {
#ifdef _DEBUG
    if(valueType != JsonType::Object && valueType != JsonType::Array){
        HANDLE_ERROR("append_list error! key:" + key + " not array or object " + to_json_string())
    }
#else

#endif
    for (const Json& j : arr) {
        children.push_back(j);
    }
}

void Json::append(const Json& json) {
#ifdef _DEBUG
    if (valueType != JsonType::Object && valueType != JsonType::Array)
    {
        HANDLE_ERROR("append_list error! key:" + key + " not array or object " + to_json_string())
    }
#else
#endif
    children.push_back(json);
}
void Json::prepend(const Json& json) {
#ifdef _DEBUG
    if (valueType != JsonType::Object && valueType != JsonType::Array)
    {
        HANDLE_ERROR("append_list error! key:" + key + " not array or object " + to_json_string())
    }
#else
#endif
    children.insert(children.begin(), json);
}
Json::Json(const char* val) : val(std::string(val)), valueType(String) {
}

Json::Json(std::string val) : val(std::move(val)), valueType(String) {
}

Json::Json(const int& val) : val(std::to_string(val)), valueType(Number) {
}

Json::Json(const double& val) : val(std::to_string(val)), valueType(Number) {
}

Json::Json(const bool& val) : val(val ? "true" : "false"), valueType(Bool) {
}

const Json* Json::get(const std::string& key) const {
    for (const Json& child : children) {
        if (child.key == key) {
            return &child;
        }
    }
    HANDLE_ERROR(key + " not found!" + to_json_string())
    return nullptr;
}

Json Json::array(const std::vector<Json>& children) {
    return array("", children);
}

Json Json::object(const std::vector<Json>& children) {
    return object("", children);
}

Json Json::array(std::string key, const std::vector<Json>& children) {
    Json ret;
    ret.key = std::move(key);
    ret.valueType = Array;
    ret.children = children;
    return ret;
}

Json Json::object(std::string key, const std::vector<Json>& children) {
    Json ret;
    ret.key = std::move(key);
    ret.valueType = Object;
    ret.children = children;
    return ret;
}

std::string Json::get_indent(const int& indent, const std::string& indentStr) {
    std::string ret;
    for (int i = 0; i < indent; ++i) {
        ret.append(indentStr);
    }
    return ret;
}

void Json::append_value_string(std::string& ret, const int& indent, bool isEnd, const std::string& object_split,
                               const std::string& array_split, const std::string& indentStr, JsonType fatherType) const {
    ret.append(get_indent(indent, indentStr));
    if (fatherType == Object) ret.append("\"" + key + "\"" + ": ");
    const std::string split = fatherType == Array ? array_split : object_split;
    if (valueType == String) {
        ret.append("\"" + val + "\"");
        goto end;
    }
    if (valueType == Null) {
        ret.append("null");
        goto end;
    }
    if (valueType == Number || valueType == Bool) {
        ret.append(val);
        goto end;
    }
    if (valueType == Object) {
        ret.append("{" + object_split);
        size_t n = children.size();
        if (n) {
            for (size_t i = 0; i < n - 1; ++i) {
                children[i].append_value_string(ret, indent + 2, false, object_split, array_split, indentStr, Object);
            }
            children[n - 1].append_value_string(ret, indent + 2, true, object_split, array_split, indentStr, Object);
        }
        ret.append(get_indent(indent, indentStr) + "}");
        goto end;
    }
    if (valueType == Array) {
        ret.append("[" + array_split);
        size_t n = children.size();
        if (n) {
            for (size_t i = 0; i < n - 1; ++i) {
                children[i].append_value_string(ret, indent + 1, false, object_split, array_split, indentStr, Array);
            }
            children[n - 1].append_value_string(ret, indent + 1, true, object_split, array_split, indentStr, Array);
        }
        ret.append(get_indent(indent, indentStr) + "]");
        goto end;
    }
end: if (!isEnd) ret.append(",");
    ret.append(split);
}


void handleBlank(std::string& s) {
    int n = static_cast<int>(s.length());
    bool isInStr = false;
    for (int i = n - 1; i >= 0; --i) {
        const char& c = s[i];
        if (c == '\"') isInStr = !isInStr;
        if (isInStr) continue;
        if (c == '\n' || c == '\t' || c == ' ') {
            s.erase(i, 1);
        }
    }
}

std::string Json::to_json_string(const std::string& object_split, const std::string& array_split,
    const std::string& indentStr, const int& indent) const {
    if (valueType == Bool) return val;
    if (valueType == String) return '\"' + val + '\"';
    if (valueType == Number) return val;
    if (valueType == Null) {
        if (children.size() != 0) {
            HANDLE_ERROR( "null 带有children 转成了字符串 (" + key + "," + val + ")"  + to_json_string())
        }
        return "null";
    }
    std::string ret;
    //ret.append(split);
    append_value_string(ret, indent, true, object_split, array_split, indentStr, Null);
    return ret;
}

Json::Json(std::nullptr_t) : valueType(Null), val("null") {
}

Json::Json(std::string key, std::nullptr_t) : key(std::move(key)), valueType(Null), val("null") {
}

Json::Json() = default;
//  解析的分割线----------------------------


// 如果未找到非空白字符，将 i 更新为 std::string::npos
void skip_whitespace(std::string& s, size_t& i) {
    i = s.find_first_not_of(" \t\n\r\f\v", i);
}

// 传入的 i 是  "所在的index
std::string parse_string(std::string& s, size_t& i) {
    i++; //skip '"'
    if (s[i] == '"') {
        i++;
        return "";
    }
    std::string ret;
    while (true) {
        if (s[i] == '"' && s[i - 1] != '\\') {
            break;
        }
        ret += s[i];
        i++;
    }
    i++;
    return ret;
}

std::string parse_number(std::string& s, size_t& i) {
    std::string num;
    while (isdigit(s[i])) {
        num += s[i++];
    }
    if (s[i] == '.') {
        i++;
        num += '.';
        while (isdigit(s[i])) {
            num += s[i++];
        }
    }
    return num;
}


std::optional<Json> parse_json_EX(std::string& s, size_t& i);
std::optional<Json> parse_json(const std::string& s) {
    auto& t = const_cast<std::string&>(s);
    size_t i = 0;
    return parse_json_EX(t, i);
}

std::optional<Json> parse_json_EX(std::string& s, size_t& i) {
    skip_whitespace(s, i);
    switch (s[i]) {
    case 'n': i += 4;
        return nullptr;
    case 't': i += 4;
        return true;
    case 'f': i += 5;
        return false;
    case '{': return parse_object(s, i);
    case '[': return parse_array(s, i);
    case '"': return parse_string(s, i);
    case '-': {
        i++; //skip -
        Json ret(nullptr);
        ret.valueType = Json::Number;
        ret.val = '-' + parse_number(s, i);
        return ret;
    }
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9': {
        Json ret(nullptr);
        ret.valueType = Json::Number;
        ret.val = parse_number(s, i);
        return ret;
    }
    default: {
        HANDLE_ERROR("json 解析错误! s:【" + s + "】\n")
        return std::nullopt;
    }
    }
}

std::optional<Json> parse_object(std::string& s, size_t& i) {
    i++; // skip '{'
    skip_whitespace(s, i);
    Json ret = Json::object();
    if (s[i] == '}') {
        i++;
        return ret;
    }
    while (true) {
        skip_whitespace(s, i);
        std::string key = parse_string(s, i);
        skip_whitespace(s, i);
        if (s[i] != ':') {
            HANDLE_ERROR("格式错误！")
            return std::nullopt;
        }
        i++;
        skip_whitespace(s, i);
        std::optional<Json> o_kv = parse_json_EX(s, i);
        if(!o_kv.has_value()){
            return std::nullopt;
        }
        auto& kv = o_kv.value();
        skip_whitespace(s, i);
        kv.key = key;
        ret.children.push_back(kv);
        if (s[i] == '}') {
            i++;
            break;
        }
        if (s[i] == ',') {
            i++;
        }
    }
    return ret;
}

std::optional<Json> parse_array(std::string& s, size_t& i) {
    i++; // skip '['
    skip_whitespace(s, i);
    Json ret = Json::array();
    if (s[i] == ']') {
        i++;
        return ret;
    }
    while (true) {
        skip_whitespace(s, i);
       // parseJson(s, i)
        std::optional<Json> o_kv = parse_json_EX(s, i);
        if(!o_kv.has_value()){
            return std::nullopt;
        }
        auto& kv = o_kv.value();
        ret.children.push_back(kv);
        skip_whitespace(s, i);
        if (s[i] == ']') {
            i++;
            break;
        }
        if (s[i] == ',') {
            i++;
        }
    }
    return ret;
}
std::optional<Json> parse_json_file(std::string& fileName) {
    static auto readFile = [](const std::string& path) -> std::string {
        std::ifstream infile(path, std::ios::binary | std::ios::ate);
        if (!infile.is_open()) {
            HANDLE_ERROR("找不到文件路径！" + path)
            return "";
        }
        std::streampos fileSize = infile.tellg();
        infile.seekg(0, std::ios::beg); // 将文件指针移回文件开始位置
        std::string content(fileSize, '\0'); // 预分配足够的空间
        infile.read(&content[0], fileSize); // 读取文件到字符串中
        infile.close();
        return content;
    };
    return parse_json(readFile(fileName));
}

std::optional<Json> parse_json_file(std::string&& fileName){
    return parse_json_file(fileName);
}

#undef HANDLE_ERROR

