# coding:utf-8
import numpy as np
from scipy import stats


def f_entropy(p):
    # Convert values to probability
    p = np.bincount(p) / float(p.shape[0])

    ep = stats.entropy(p)
    if ep == -float("inf"):
        return 0.0
    return ep


def information_gain(y, splits):
    splits_entropy = sum(
        [f_entropy(split) * (float(split.shape[0]) / y.shape[0]) for split in splits]
    )
    return f_entropy(y) - splits_entropy


def mse_criterion(y, splits):
    y_mean = np.mean(y)
    return -sum(
        [
            np.sum((split - y_mean) ** 2) * (float(split.shape[0]) / y.shape[0])
            for split in splits
        ]
    )


def xgb_criterion(y, left, right, loss):
    left = loss.gain(left["actual"], left["y_pred"])
    right = loss.gain(right["actual"], right["y_pred"])
    initial = loss.gain(y["actual"], y["y_pred"])
    gain = left + right - initial
    return gain


def get_split_mask(X, column, value):
    left_mask = X[:, column] < value
    right_mask = X[:, column] >= value
    return left_mask, right_mask


def split(X, y, value):
    left_mask = X < value
    right_mask = X >= value
    return y[left_mask], y[right_mask]


def split_dataset(X, target, column, value, return_X=True):
    left_mask, right_mask = get_split_mask(X, column, value)

    left, right = {}, {}
    for key in target.keys():
        left[key] = target[key][left_mask]
        right[key] = target[key][right_mask]

    if return_X:
        left_X, right_X = X[left_mask], X[right_mask]
        return left_X, right_X, left, right
    else:
        return left, right
