#include "evaluation.h"
#include "eval_op_prototypes.h"

evaluation::evaluation(const std::vector<expression> &exprs) {
    try {
        std::cout << "Starting evaluation construction with " << exprs.size() << " expressions." << std::endl;
        for (auto &expr: exprs) {
            std::cout << "Processing expression with ID: " << expr.get_expr_id() << std::endl;
            std::shared_ptr<eval_op> p = eval_op_prototypes::instance().locate(expr.get_op_type());
            ops_.push_back(p->clone(expr));
            std::cout << "Expression with ID: " << expr.get_expr_id() << " processed successfully." << std::endl;
}
        std::cout << "Evaluation construction completed successfully." << std::endl;
    } catch (const std::runtime_error& e) {
        std::cerr << "Failed to construct evaluation: " << e.what() << std::endl;
    }
}

void evaluation::add_kwargs_double(
    const char *key,
    double value)
{
    tensor scalar(value);
    kwargs_[key] = scalar;
}

void evaluation::add_kwargs_ndarray(
    const char *key,
    int dim,
    size_t shape[],
    double data[])
{
    tensor ndarray(dim, shape, data);
    kwargs_[key] = ndarray;
}

tensor &evaluation::get_result() 
{ 
    if (!variables_.empty()) {
        int last_expr_id = std::prev(variables_.end())->first;
        std::cout << "Returning result from the last expression with ID: " << last_expr_id << std::endl;
        return variables_[last_expr_id];
    }
    throw std::runtime_error("No result available."); 
}

int evaluation::execute()
{
    std::cout << "Executing evaluation with " << ops_.size() << " operations.\n";
    variables_.clear();

    for (auto &op : ops_) {
        std::cout << "Evaluating operation of type: " << typeid(*op).name() << "\n";
        op->eval(variables_, kwargs_);
        std::cout << "Operation evaluation complete. Variables size: " << variables_.size() << "\n";
    }

    std::cout << "Evaluation complete. Total variables evaluated: " << variables_.size() << "\n";
    return 0;
}