from sklearn.model_selection import RandomizedSearchCV, KFold
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import accuracy_score, make_scorer
from pathlib import Path

def write_hpValues(model_Name, HP_Values,dataset):
    Path("results/%s" % dataset).mkdir(parents=True, exist_ok=True)
    Path("results/%s/%s" % (dataset,model_Name)).mkdir(parents=True, exist_ok=True)
    file_name = r'results/%s/%s/BestParam.txt' % (dataset,model_Name)
    with open(file_name, 'a+') as x_file:
        x_file.write(str(HP_Values))
        x_file.write("\n----------------------------------------------------------")
    return 0


# parameters grid to select the best combination using the listed values
def GradientBoosting_hyperparameterTuning(X_train, Y_train,dataset):
    grid_Param={'n_estimators': [10,100,500,800,1500,2000,3000,5000],
                'criterion': ['friedman_mse','mse','mae'],
                'loss': ['deviance', 'exponential'],
                'learning_rate':[1, 0.5, 0.25, 0.1, 0.05, 0.01],
                'max_features':['auto','sqrt','log2'],
                'max_depth': [10,20,30,50,70,100,200,300,400],
                'min_samples_split': [0.1,4,7,10,20,30,35,50,100,200],
                'min_samples_leaf': [1,4,7,9,15,20,30,40,50]}

    kfold = KFold(n_splits=5, shuffle=True, random_state=42)
    GradientBoosting = GradientBoostingClassifier()
    grid_search = RandomizedSearchCV(estimator= GradientBoosting, param_distributions=grid_Param, n_iter=100, cv=kfold, verbose=2, random_state=42 , scoring='accuracy',error_score=0, n_jobs=-1)
    grid_search.fit(X_train, Y_train)
    best_grid = grid_search.best_estimator_
    write_hpValues('GradientBoosting', str(best_grid),dataset)

    print(grid_search.best_estimator_)
    return grid_search


def GradientBoosting_training_tuning(X_train,Y_train,dataset):

    best_grid = 0
    write_hpValues('GradientBoosting', best_grid,dataset)

    Trained_model = GradientBoostingClassifier(criterion='mae', learning_rate=0.01,
                               loss='exponential', max_depth=70,
                               max_features='auto', min_samples_split=20,
                               n_estimators=100)
    Trained_model.fit(X_train,Y_train)
    return Trained_model
