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


def random_forest(df):
    param_grid = {'n_estimators': [10, 50, 100],
                  'max_depth': [None, 10, 20],
                  'min_samples_split': [2, 5, 10],
                  'criterion': ['gini', 'entropy', 'log_loss']}
    X = df[['X1_ActualPosition', 'X1_ActualVelocity', 'X1_ActualAcceleration', 'X1_CommandPosition',
                    'X1_CommandVelocity', 'X1_CurrentFeedback', 'X1_DCBusVoltage',
                    'X1_OutputCurrent', 'X1_OutputVoltage', 'X1_OutputPower', 'Y1_ActualPosition', 'Y1_ActualVelocity',
                    'Y1_CommandPosition', 'Y1_CommandVelocity',
                    'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage', 'Y1_OutputPower',
                    'Z1_ActualPosition', 'Z1_ActualVelocity', 'Z1_CommandPosition',
                    'Z1_CommandVelocity',
                    'S1_ActualPosition', 'S1_ActualVelocity',
                    'S1_ActualAcceleration', 'S1_CommandPosition', 'S1_CommandVelocity',
                    'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                    'M1_CURRENT_PROGRAM_NUMBER', 'M1_sequence_number', 'M1_CURRENT_FEEDRATE',
                    'Machining_Process', 'feedrate', 'clamp_pressure']]
    y = df["tool_condition"]
    X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, random_state=42)
    model = RandomForestClassifier(max_depth=20, min_samples_split=2, n_estimators=100, criterion='entropy')
    #grid_search = GridSearchCV(model, param_grid=param_grid, cv=5)

    # Fit the model with the parameter grid
    #grid_search.fit(X_train, y_train)

    # Print the best hyperparameters and their corresponding score
    #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):
    param_grid = {'n_neighbors': [5, 10, 15, 40],
                  'weights': ['uniform', 'distance']}
    X = df[['X1_ActualPosition', 'X1_ActualVelocity', 'X1_ActualAcceleration', 'X1_CommandPosition',
                    'X1_CommandVelocity', 'X1_CurrentFeedback', 'X1_DCBusVoltage',
                    'X1_OutputCurrent', 'X1_OutputVoltage', 'X1_OutputPower', 'Y1_ActualPosition', 'Y1_ActualVelocity',
                    'Y1_CommandPosition', 'Y1_CommandVelocity',
                    'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage', 'Y1_OutputPower',
                    'Z1_ActualPosition', 'Z1_ActualVelocity', 'Z1_CommandPosition',
                    'Z1_CommandVelocity',
                    'S1_ActualPosition', 'S1_ActualVelocity',
                    'S1_ActualAcceleration', 'S1_CommandPosition', 'S1_CommandVelocity',
                    'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                    'M1_CURRENT_PROGRAM_NUMBER', 'M1_sequence_number', 'M1_CURRENT_FEEDRATE',
                    'Machining_Process', 'feedrate', 'clamp_pressure']]
    y = df["tool_condition"]
    X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, random_state=42)
    model = neighbors.KNeighborsClassifier(n_neighbors=10, 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):
    param_grid = {'splitter': ['best', 'random'],
                  'max_depth': [None, 10, 20],
                  'min_samples_split': [2, 5, 10],
                  'criterion': ['gini', 'entropy', 'log_loss']}
    X = df[['X1_ActualPosition', 'X1_ActualVelocity', 'X1_ActualAcceleration', 'X1_CommandPosition',
                    'X1_CommandVelocity', 'X1_CurrentFeedback', 'X1_DCBusVoltage',
                    'X1_OutputCurrent', 'X1_OutputVoltage', 'X1_OutputPower', 'Y1_ActualPosition', 'Y1_ActualVelocity',
                    'Y1_CommandPosition', 'Y1_CommandVelocity',
                    'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage', 'Y1_OutputPower',
                    'Z1_ActualPosition', 'Z1_ActualVelocity', 'Z1_CommandPosition',
                    'Z1_CommandVelocity',
                    'S1_ActualPosition', 'S1_ActualVelocity',
                    'S1_ActualAcceleration', 'S1_CommandPosition', 'S1_CommandVelocity',
                    'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                    'M1_CURRENT_PROGRAM_NUMBER', 'M1_sequence_number', 'M1_CURRENT_FEEDRATE',
                    'Machining_Process', 'feedrate', 'clamp_pressure']]
    y = df["tool_condition"]
    X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, random_state=42)
    model = DecisionTreeClassifier(criterion='entropy', 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):
    param_grid = {'penalty': [None, 'l2'],
                  'solver': ['sag', 'saga', 'lbfgs', 'newton-cg', 'newton-cholesky']}
    X = df[['X1_ActualPosition', 'X1_ActualVelocity', 'X1_ActualAcceleration', 'X1_CommandPosition',
                    'X1_CommandVelocity', 'X1_CurrentFeedback', 'X1_DCBusVoltage',
                    'X1_OutputCurrent', 'X1_OutputVoltage', 'X1_OutputPower', 'Y1_ActualPosition', 'Y1_ActualVelocity',
                    'Y1_CommandPosition', 'Y1_CommandVelocity',
                    'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage', 'Y1_OutputPower',
                    'Z1_ActualPosition', 'Z1_ActualVelocity', 'Z1_CommandPosition',
                    'Z1_CommandVelocity',
                    'S1_ActualPosition', 'S1_ActualVelocity',
                    'S1_ActualAcceleration', 'S1_CommandPosition', 'S1_CommandVelocity',
                    'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                    'M1_CURRENT_PROGRAM_NUMBER', 'M1_sequence_number', 'M1_CURRENT_FEEDRATE',
                    'Machining_Process', 'feedrate', 'clamp_pressure']]
    y = df["tool_condition"]
    X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, random_state=42)
    model = LogisticRegression(penalty='l2', solver='lbfgs', max_iter=2000)
    # 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):
    param_grid = {'probability': [True, False],
                  'shrinking': [True, False],
                  'kernel': ['linear', 'poly', 'rbf', 'sigmoid', 'precomputed']}
    X = df[['X1_ActualPosition', 'X1_ActualVelocity', 'X1_ActualAcceleration', 'X1_CommandPosition',
                    'X1_CommandVelocity', 'X1_CurrentFeedback', 'X1_DCBusVoltage',
                    'X1_OutputCurrent', 'X1_OutputVoltage', 'X1_OutputPower', 'Y1_ActualPosition', 'Y1_ActualVelocity',
                    'Y1_CommandPosition', 'Y1_CommandVelocity',
                    'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage', 'Y1_OutputPower',
                    'Z1_ActualPosition', 'Z1_ActualVelocity', 'Z1_CommandPosition',
                    'Z1_CommandVelocity',
                    'S1_ActualPosition', 'S1_ActualVelocity',
                    'S1_ActualAcceleration', 'S1_CommandPosition', 'S1_CommandVelocity',
                    'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                    'M1_CURRENT_PROGRAM_NUMBER', 'M1_sequence_number', 'M1_CURRENT_FEEDRATE',
                    'Machining_Process', 'feedrate', 'clamp_pressure']]
    y = df["tool_condition"]
    X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, random_state=42)
    model = SVC(probability=False, shrinking=False, kernel='rbf')
    #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 nbayes_classification(df):
    X = df[['X1_ActualPosition', 'X1_ActualVelocity', 'X1_ActualAcceleration', 'X1_CommandPosition',
                    'X1_CommandVelocity', 'X1_CurrentFeedback', 'X1_DCBusVoltage',
                    'X1_OutputCurrent', 'X1_OutputVoltage', 'X1_OutputPower', 'Y1_ActualPosition', 'Y1_ActualVelocity',
                    'Y1_CommandPosition', 'Y1_CommandVelocity',
                    'Y1_DCBusVoltage', 'Y1_OutputCurrent', 'Y1_OutputVoltage', 'Y1_OutputPower',
                    'Z1_ActualPosition', 'Z1_ActualVelocity', 'Z1_CommandPosition',
                    'Z1_CommandVelocity',
                    'S1_ActualPosition', 'S1_ActualVelocity',
                    'S1_ActualAcceleration', 'S1_CommandPosition', 'S1_CommandVelocity',
                    'S1_CurrentFeedback', 'S1_DCBusVoltage', 'S1_OutputCurrent', 'S1_OutputVoltage', 'S1_OutputPower',
                    'M1_CURRENT_PROGRAM_NUMBER', 'M1_sequence_number', 'M1_CURRENT_FEEDRATE',
                    'Machining_Process', 'feedrate', 'clamp_pressure']]
    y = df["tool_condition"]
    X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, random_state=42)
    model = naive_bayes.GaussianNB()
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    return y_test, y_pred
