import ast
import pandas as pd
import numpy as np

#ML models
from xgboost import XGBClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC

#Data scaling
from sklearn.preprocessing import MinMaxScaler, StandardScaler, RobustScaler

#oversampling
#from imblearn.combine import SMOTETomek
from  imblearn.over_sampling import SMOTE
from sklearn.utils import shuffle
from sklearn.model_selection import train_test_split

# scale  data of each portion of dataset (train, evaluation and test)
def scale_data(train, evaluation, test):
    scaler = StandardScaler()
    X_train = pd.DataFrame(scaler.fit_transform(train), columns=train.columns)
    # scale train and test
    X_eval = pd.DataFrame(scaler.transform(evaluation), columns=evaluation.columns)
    X_test = pd.DataFrame(scaler.transform(test), columns=test.columns)
    return X_train, X_eval, X_test


# oversample dataset portion
# used in separated form for train and evalution datasets
# do not use in test data at all
def oversample(data, target):
    smk = SMOTE()
    data, target = smk.fit_resample(data, target)
    return data, target


# read data from csv file and make split 80/20
def read_data(filename, known_features=True):
    # read the csv file that was combined with word2vec and graph features
    df = pd.read_csv(filename, header=0)

    # random shuffle the dataframe
    df = shuffle(df)

    # extract target from datafrmae
    target = df["target"]

    df = df.drop(["target"], axis="columns")
    if known_features:
        # feature_list = ast.literal_eval(open("june2021_freq_features_sorted", "r").read())[:242]
        feature_list = ast.literal_eval(open("selected_features.txt", "r").read())
        df = df[feature_list]

    # make stratified train and test split 80/20
    X_train, X_test, y_train, y_test = train_test_split(df,
                                                        target,
                                                        test_size=0.2,
                                                        stratify=target)

    return X_train, y_train, X_test, y_test

def parse_model_params(model):
    data = open("model_fine_tune_results.txt", "r").read()
    result = {}
    if model == "rfor":
        data = data.split("Model:rfor\n")[1].split("By both:")[1].split("\n")[0].split("params:")[1]
        result["n_estimators"] = int(data.split("nEst:")[1].split(" ")[0])
        result["criterion"] = data.split("criterion:")[1].split(" ")[0]
        result["ccp_alpha"] = float(data.split("cAplha:")[1].split(" ")[0])
        result["min_samples_split"] = int(data.split("mSplit:")[1])
    if model == "svm":
        data = data.split("Model:svm\n")[1].split("By both:")[1].split("\n")[0].split("params:")[1]
        result["kernel"] = data.split("kernel:")[1].split(" ")[0]
        result["C"] = data.split("C:")[1]
        if "." in result["C"]:
            result["C"] = float(result["C"])
        else:
            result["C"] = int(result["C"])
    if model == "xgboost":
        data = data.split("Model:xgboost\n")[1].split("By both:")[1].split("\n")[0].split("params:")[1]
        result["objective"] = data.split("Obj:")[1].split(" ")[0]
        result["learning_rate"] = float(data.split("LR:")[1].split(" ")[0])

        result["n_estimators"] = int(data.split("nEst:")[1].split(" ")[0])
        result["max_depth"] = int(data.split("mDepth:")[1].split(" ")[0])
        result["colsample_bytree"] = float(data.split("cSample:")[1].split(" ")[0])
        result["eval_metric"] = data.split("eval:")[1]
    return result

def get_xgboost_model(objective,learning_rate,n_estimators,max_depth,colsample_bytree,eval_metric, num_class=2,gpu=False):
    if gpu:
        return XGBClassifier(objective=objective,
                              num_class=num_class,
                              learning_rate=learning_rate,
                              n_estimators=n_estimators,
                              max_depth=max_depth,
                              colsample_bytree=colsample_bytree,
                              eval_metric=eval_metric,
                              tree_method="gpu_hist", #SERVER ONLY
                              predictor = 'gpu_predictor',#SERVER ONLY
                              use_label_encoder=False)
    else:
        return XGBClassifier(objective=objective,
                              num_class=num_class,
                              learning_rate=learning_rate,
                              n_estimators=n_estimators,
                              max_depth=max_depth,
                              colsample_bytree=colsample_bytree,
                              eval_metric=eval_metric,
                              use_label_encoder=False)

def get_svm_model(kernel, C):
    return SVC(kernel=kernel, C=C, probability=True)

def get_rfor_model(n_estimators,criterion,ccp_alpha,min_samples_split):
    return RandomForestClassifier(n_estimators=n_estimators,
                                criterion=criterion,ccp_alpha=ccp_alpha,
                                min_samples_split=min_samples_split)
