#pragma once
#include <numeric>
#include <vector>
#include <iostream>
#include <iterator>
#include <limits>
#include <algorithm>
#include <set>
#include <tuple>
using namespace std;

/**
 * @brief Bast structure for a node.
 *
 * @tparam PartyType Type of party.
 */
template <typename PartyType>
struct Node
{
    vector<PartyType> parties;
    vector<float> y;
    vector<int> idxs;

    int num_classes;
    int depth;
    int active_party_id;
    int n_job;

    int party_id, record_id;
    int row_count, num_parties;
    float score;
    vector<float> val;

    int best_party_id = -1;
    int best_col_id = -1;
    int best_threshold_id = -1;

    float best_score = -1 * numeric_limits<float>::infinity();
    int is_leaf_flag = -1; // -1:not calculated yer, 0: is not leaf, 1: is leaf

    Node(){};

    /**
     * @brief Get the idxs object
     *
     * @return vector<int>
     */
    virtual vector<int> get_idxs() = 0;

    /**
     * @brief Get the party id object
     *
     * @return int
     */
    virtual int get_party_id() = 0;

    /**
     * @brief Get the record id object
     *
     * @return int
     */
    virtual int get_record_id() = 0;

    /**
     * @brief Get the value assigned to this node.
     *
     * @return float
     */
    virtual vector<float> get_val() = 0;

    /**
     * @brief Get the evaluation score of this node.
     *
     * @return float
     */
    virtual float get_score() = 0;

    /**
     * @brief Get the num of parties used for this node.
     *
     * @return int
     */
    virtual int get_num_parties() = 0;

    /**
     * @brief Compute the weight (val) of this node.
     *
     * @return vector<float>
     */
    virtual vector<float> compute_weight() = 0;

    /**
     * @brief Find the best split which gives the best score (gain).
     *
     * @return tuple<int, int, int>
     */
    virtual tuple<int, int, int> find_split() = 0;

    /**
     * @brief Generate the children nodes.
     *
     * @param best_party_id The index of the best party.
     * @param best_col_id The index of the best feature.
     * @param best_threshold_id The index of the best threshold.
     */
    virtual void make_children_nodes(int best_party_id, int best_col_id, int best_threshold_id) = 0;

    /**
     * @brief Return true if this node is a leaf.
     *
     * @return true
     * @return false
     */
    virtual bool is_leaf() = 0;

    /**
     * @brief Return true if the node is pure; the assigned labels to this node consist of a unique label.
     *
     * @return true
     * @return false
     */
    virtual bool is_pure() = 0;
};
