/*
 * Copyright 2022 The casbin Authors. All Rights Reserved.
 *
 * Licensed 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.
 */
#include "casbin/model/evaluator.h"

#include <regex>

#include "casbin/util/util.h"

namespace casbin {
bool ExprtkEvaluator::Eval(const std::string& expression_string) {
    expression.register_symbol_table(symbol_table);
    if (enable_get) {
        expression.register_symbol_table(glbl_variable_symbol_table);
    }

    if (this->expression_string_ != expression_string) {
        this->expression_string_ = expression_string;
        // replace (&& -> and), (|| -> or)
        auto replaced_string = std::regex_replace(expression_string, std::regex("&&"), "and");
        replaced_string = std::regex_replace(replaced_string, std::regex("\\|{2}"), "or");
        // replace string "" -> ''
        replaced_string = std::regex_replace(replaced_string, std::regex("\""), "\'");

        return parser.compile(replaced_string, expression);
    }

    return this->parser.error_count() == 0;
}

void ExprtkEvaluator::InitialObject(const std::string& identifier) {
    // symbol_table.add_stringvar("");
}

void ExprtkEvaluator::EnableGet(const std::string& identifier) {
    enable_get = true;
    if (identifier.empty()) {
        glbl_variable_symbol_table.add_stringvar("key_get_result", key_get_result);
    } else {
        glbl_variable_symbol_table.add_stringvar(identifier, key_get_result);
    }
}

void ExprtkEvaluator::PushObjectString(const std::string& target, const std::string& proprity, const std::string& var) {
    auto identifier = target + "." + proprity;

    this->AddIdentifier(identifier, var);
}

void ExprtkEvaluator::PushObjectJson(const std::string& target, const std::string& proprity, const nlohmann::json& var) {
    auto identifier = target + "." + proprity;
    
    // Recursively flatten JSON object into dot-notation identifiers
    if (var.is_object()) {
        for (auto& [key, value] : var.items()) {
            PushObjectJson(identifier, key, value);
        }
    } else if (var.is_string()) {
        this->AddIdentifier(identifier, var.get<std::string>());
    } else if (var.is_number()) {
        // Get as double first to preserve precision, then cast to numerical_type
        this->AddNumericIdentifier(identifier, static_cast<numerical_type>(var.get<double>()));
    } else if (var.is_boolean()) {
        this->AddNumericIdentifier(identifier, static_cast<numerical_type>(var.get<bool>() ? 1 : 0));
    }
    // For other types (arrays, null, etc.), we skip them as they're not supported in the expression evaluator
}

void ExprtkEvaluator::LoadFunctions() {
    AddFunction("keyMatch", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch, 2));
    AddFunction("keyMatch2", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch2, 2));
    AddFunction("keyMatch3", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch3, 2));
    AddFunction("keyMatch4", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch4, 2));
    AddFunction("regexMatch", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::RegexMatch, 2));
    AddFunction("ipMatch", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::IpMatch, 2));
    AddFunction("keyGet", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyGet, 2));
    AddFunction("keyGet2", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyGet2, 3));
    AddFunction("keyGet3", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyGet3, 3));
}

void ExprtkEvaluator::LoadGFunction(std::shared_ptr<RoleManager> rm, const std::string& name, int narg) {
    auto func = ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::Gfunction, narg, rm);
    this->AddFunction(name, func);
}

void ExprtkEvaluator::ProcessFunctions(const std::string& expression) {
}

Type ExprtkEvaluator::CheckType() {
    if (parser.error_count() != 0) {
        throw parser.error();
    }
    if (expression.value() == float(0) || expression.value() == float(1)) {
        return Type::Bool;
    } else {
        return Type::Float;
    }
}

bool ExprtkEvaluator::GetBoolean() {
    return bool(this->expression);
}

float ExprtkEvaluator::GetFloat() {
    return expression.value();
}

std::string ExprtkEvaluator::GetString() {
    const numerical_type result = expression.value();
    return key_get_result;
}

void ExprtkEvaluator::Clean(AssertionMap& section, bool after_enforce) {
    if (!after_enforce) {
        return;
    }

    this->symbol_table.clear();
    this->glbl_variable_symbol_table.clear();
    this->expression_string_ = "";
    this->Functions.clear();
    this->identifiers_.clear();
    this->numeric_identifiers_.clear();
}

void ExprtkEvaluator::AddFunction(const std::string& func_name, std::shared_ptr<exprtk_func_t> func) {
    if (func != nullptr) {
        this->Functions.push_back(func);
        symbol_table.add_function(func_name, *func);
    }
}

void ExprtkEvaluator::PrintSymbol() {
    std::vector<std::string> var_list;
    symbol_table.get_stringvar_list(var_list);

    printf("Current symboltable: \n");
    for (auto& var : var_list) {
        printf(" %s: %s\n", var.c_str(), symbol_table.get_stringvar(var)->ref().c_str());
    }
    printf("Current error: %s\n", parser.error().c_str());
    // printf("Current exprsio string: %s\n", parser.current_token);
    printf("Current value: %d\n", bool(this->expression));
}

std::unordered_map<std::string, std::string> ExprtkEvaluator::requestValues() const {
    std::vector<std::string> var_list;
    symbol_table.get_stringvar_list(var_list);
    std::unordered_map<std::string, std::string> result;
    for (const auto& e : var_list ) {
       if (e[0] == 'r') {
            auto token = e.substr(2, e.size() - 2);
	    auto value = symbol_table.get_stringvar("r." + token)->ref().c_str();
            result.emplace(token, value);
        }
    }
    return result;
}


void ExprtkEvaluator::AddIdentifier(const std::string& identifier, const std::string& var) {
    if (!symbol_table.symbol_exists(identifier)) {
        identifiers_[identifier] = std::make_unique<std::string>("");
        this->symbol_table.add_stringvar(identifier, *identifiers_[identifier]);
    }
    symbol_table.get_stringvar(identifier)->ref() = var;
}

void ExprtkEvaluator::AddNumericIdentifier(const std::string& identifier, numerical_type value) {
    if (!symbol_table.symbol_exists(identifier)) {
        numeric_identifiers_[identifier] = std::make_unique<numerical_type>(0);
        this->symbol_table.add_variable(identifier, *numeric_identifiers_[identifier]);
    }
    *numeric_identifiers_[identifier] = value;
}

} // namespace casbin
