from sklearn.linear_model import LogisticRegression
import numpy as np
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn import neighbors, naive_bayes
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.neural_network import MLPClassifier


def random_forest(df, df_test):
    param_grid = {'min_samples_split': [7, 14],
                  'max_features': [5, 10, 20],
                  'criterion': ['gini', 'entropy']}
    X_train = df[['X1_ActualPosition', 'X1_CommandPosition',
                  'X1_DCBusVoltage',
                  'X1_OutputCurrent', 'Y1_ActualPosition',
                  'Y1_CommandPosition',
                  'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                  'Z1_ActualPosition', 'Z1_CommandPosition',
                  'S1_ActualVelocity',
                  'S1_ActualAcceleration', 'S1_CommandVelocity',
                  'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                  'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_train = df["tool_condition"]
    X_test = df_test[['X1_ActualPosition', 'X1_CommandPosition',
                      'X1_DCBusVoltage',
                      'X1_OutputCurrent', 'Y1_ActualPosition',
                      'Y1_CommandPosition',
                      'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                      'Z1_ActualPosition', 'Z1_CommandPosition',
                      'S1_ActualVelocity',
                      'S1_ActualAcceleration', 'S1_CommandVelocity',
                      'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                      'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_test = df_test["tool_condition"]
    model = RandomForestClassifier(max_depth=None, min_samples_split=7, n_estimators=400, criterion='gini',
                                   max_features=5)
    # grid_search = GridSearchCV(model, param_grid=param_grid, cv=3, n_jobs=8)
    # grid_search.fit(X_train, y_train)
    # print('Best parameters:', grid_search.best_params_)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    return y_test, y_pred


def knn_regression(df, df_test):
    param_grid = {'n_neighbors': [8, 10, 12],
                  'weights': ['uniform', 'distance']}
    X_train = df[['X1_ActualPosition', 'X1_CommandPosition',
                  'X1_DCBusVoltage',
                  'X1_OutputCurrent', 'Y1_ActualPosition',
                  'Y1_CommandPosition',
                  'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                  'Z1_ActualPosition', 'Z1_CommandPosition',
                  'S1_ActualVelocity',
                  'S1_ActualAcceleration', 'S1_CommandVelocity',
                  'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                  'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_train = df["tool_condition"]
    X_test = df_test[['X1_ActualPosition', 'X1_CommandPosition',
                      'X1_DCBusVoltage',
                      'X1_OutputCurrent', 'Y1_ActualPosition',
                      'Y1_CommandPosition',
                      'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                      'Z1_ActualPosition', 'Z1_CommandPosition',
                      'S1_ActualVelocity',
                      'S1_ActualAcceleration', 'S1_CommandVelocity',
                      'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                      'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_test = df_test["tool_condition"]
    model = neighbors.KNeighborsClassifier(n_neighbors=8, weights='distance')
    # grid_search = GridSearchCV(model, param_grid=param_grid, cv=5)
    # grid_search.fit(X_train, y_train)
    # print('Best parameters:', grid_search.best_params_)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    return y_test, y_pred


def decision_tree(df, df_test):
    param_grid = {'splitter': ['best', 'random'],
                  'max_depth': [None, 10, 20],
                  'min_samples_split': [2, 5, 10],
                  'criterion': ['gini', 'entropy', 'log_loss']}
    X_train = df[['X1_ActualPosition', 'X1_CommandPosition',
                  'X1_DCBusVoltage',
                  'X1_OutputCurrent', 'Y1_ActualPosition',
                  'Y1_CommandPosition',
                  'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                  'Z1_ActualPosition', 'Z1_CommandPosition',
                  'S1_ActualVelocity',
                  'S1_ActualAcceleration', 'S1_CommandVelocity',
                  'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                  'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_train = df["tool_condition"]
    X_test = df_test[['X1_ActualPosition', 'X1_CommandPosition',
                      'X1_DCBusVoltage',
                      'X1_OutputCurrent', 'Y1_ActualPosition',
                      'Y1_CommandPosition',
                      'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                      'Z1_ActualPosition', 'Z1_CommandPosition',
                      'S1_ActualVelocity',
                      'S1_ActualAcceleration', 'S1_CommandVelocity',
                      'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                      'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_test = df_test["tool_condition"]
    model = DecisionTreeClassifier(criterion='log_loss', max_depth=None, min_samples_split=2, splitter='best')
    # grid_search = GridSearchCV(model, param_grid=param_grid, cv=5)
    # grid_search.fit(X_train, y_train)
    # print('Best parameters:', grid_search.best_params_)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    return y_test, y_pred


def logistic_regression(df, df_test):
    param_grid = {'penalty': [None, 'l2'],
                  'solver': ['sag', 'saga', 'lbfgs', 'newton-cg', 'newton-cholesky']}
    X_train = df[['X1_ActualPosition', 'X1_CommandPosition',
                  'X1_DCBusVoltage',
                  'X1_OutputCurrent', 'Y1_ActualPosition',
                  'Y1_CommandPosition',
                  'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                  'Z1_ActualPosition', 'Z1_CommandPosition',
                  'S1_ActualVelocity',
                  'S1_ActualAcceleration', 'S1_CommandVelocity',
                  'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                  'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_train = df["tool_condition"]
    X_test = df_test[['X1_ActualPosition', 'X1_CommandPosition',
                      'X1_DCBusVoltage',
                      'X1_OutputCurrent', 'Y1_ActualPosition',
                      'Y1_CommandPosition',
                      'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                      'Z1_ActualPosition', 'Z1_CommandPosition',
                      'S1_ActualVelocity',
                      'S1_ActualAcceleration', 'S1_CommandVelocity',
                      'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                      'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_test = df_test["tool_condition"]
    model = LogisticRegression(penalty=None, solver='saga', max_iter=10000)
    # grid_search = GridSearchCV(model, param_grid=param_grid, cv=5)
    # grid_search.fit(X_train, y_train)
    # print('Best parameters:', grid_search.best_params_)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    return y_test, y_pred


def svm_classification(df, df_test):
    param_grid = {'probability': [True, False],
                  'shrinking': [True, False],
                  'kernel': ['poly', 'rbf', 'sigmoid', 'linear']}
    X_train = df[['X1_ActualPosition', 'X1_CommandPosition',
                  'X1_DCBusVoltage',
                  'X1_OutputCurrent', 'Y1_ActualPosition',
                  'Y1_CommandPosition',
                  'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                  'Z1_ActualPosition', 'Z1_CommandPosition',
                  'S1_ActualVelocity',
                  'S1_ActualAcceleration', 'S1_CommandVelocity',
                  'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                  'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_train = df["tool_condition"]
    X_test = df_test[['X1_ActualPosition', 'X1_CommandPosition',
                      'X1_DCBusVoltage',
                      'X1_OutputCurrent', 'Y1_ActualPosition',
                      'Y1_CommandPosition',
                      'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                      'Z1_ActualPosition', 'Z1_CommandPosition',
                      'S1_ActualVelocity',
                      'S1_ActualAcceleration', 'S1_CommandVelocity',
                      'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                      'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_test = df_test["tool_condition"]
    model = SVC(probability=True, shrinking=True, kernel='rbf')
    # grid_search = GridSearchCV(model, param_grid=param_grid, cv=3, n_jobs=4)
    # grid_search.fit(X_train, y_train)
    # print('Best parameters:', grid_search.best_params_)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    return y_test, y_pred


def nbayes_classification(df, df_test):
    param_grid = {'var_smoothing': np.logspace(0, -9, num=100)}
    X_train = df[['X1_ActualPosition', 'X1_CommandPosition',
                  'X1_DCBusVoltage',
                  'X1_OutputCurrent', 'Y1_ActualPosition',
                  'Y1_CommandPosition',
                  'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                  'Z1_ActualPosition', 'Z1_CommandPosition',
                  'S1_ActualVelocity',
                  'S1_ActualAcceleration', 'S1_CommandVelocity',
                  'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                  'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_train = df["tool_condition"]
    X_test = df_test[['X1_ActualPosition', 'X1_CommandPosition',
                      'X1_DCBusVoltage',
                      'X1_OutputCurrent', 'Y1_ActualPosition',
                      'Y1_CommandPosition',
                      'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                      'Z1_ActualPosition', 'Z1_CommandPosition',
                      'S1_ActualVelocity',
                      'S1_ActualAcceleration', 'S1_CommandVelocity',
                      'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                      'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_test = df_test["tool_condition"]
    model = naive_bayes.GaussianNB(var_smoothing=0.1873817422860384)
    # grid_search = GridSearchCV(model, param_grid=param_grid, cv=3, n_jobs=4)
    # grid_search.fit(X_train, y_train)
    # print('Best parameters:', grid_search.best_params_)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    return y_test, y_pred


def ann_network(df, df_test):
    param_grid = {'hidden_layer_sizes': np.arange(10, 15),
                  'random_state': [0, 3, 6, 9]}
    X_train = df[['X1_ActualPosition', 'X1_CommandPosition',
                  'X1_DCBusVoltage',
                  'X1_OutputCurrent', 'Y1_ActualPosition',
                  'Y1_CommandPosition',
                  'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                  'Z1_ActualPosition', 'Z1_CommandPosition',
                  'S1_ActualVelocity',
                  'S1_ActualAcceleration', 'S1_CommandVelocity',
                  'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                  'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_train = df["tool_condition"]
    X_test = df_test[['X1_ActualPosition', 'X1_CommandPosition',
                      'X1_DCBusVoltage',
                      'X1_OutputCurrent', 'Y1_ActualPosition',
                      'Y1_CommandPosition',
                      'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage',
                      'Z1_ActualPosition', 'Z1_CommandPosition',
                      'S1_ActualVelocity',
                      'S1_ActualAcceleration', 'S1_CommandVelocity',
                      'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                      'M1_sequence_number', 'feedrate', 'clamp_pressure']]
    y_test = df_test["tool_condition"]
    model = MLPClassifier(max_iter=1000, hidden_layer_sizes=13, random_state=9)
    #grid_search = GridSearchCV(model, param_grid=param_grid, cv=3, n_jobs=8)
    #grid_search.fit(X_train, y_train)
    #print('Best parameters:', grid_search.best_params_)
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    return y_test, y_pred
