import time
from datetime import datetime
import tensorflow as tf
from tensorflow.keras.layers import Dense, Dropout, LSTM
from tensorflow.keras.models import Sequential
from tensorflow.keras.callbacks import CSVLogger
from kerastuner.tuners import RandomSearch
from kerastuner.engine.hyperparameters import HyperParameters

# Define the tuning process
def build_model(hp):
    model = Sequential()
    model.add(LSTM(units=hp.Int('units_1', min_value=32, max_value=256, step=32), activation='relu', return_sequences=True, input_shape=(x_train.shape[1], 1)))
    model.add(Dropout(hp.Float('dropout_1', min_value=0.1, max_value=0.5, step=0.1)))

    model.add(LSTM(units=hp.Int('units_2', min_value=32, max_value=256, step=32), activation='relu', return_sequences=True))
    model.add(Dropout(hp.Float('dropout_2', min_value=0.1, max_value=0.5, step=0.1)))

    model.add(LSTM(units=hp.Int('units_3', min_value=32, max_value=256, step=32), activation='relu', return_sequences=True))
    model.add(Dropout(hp.Float('dropout_3', min_value=0.1, max_value=0.5, step=0.1)))

    model.add(LSTM(units=hp.Int('units_4', min_value=32, max_value=256, step=32), activation='relu'))
    model.add(Dropout(hp.Float('dropout_4', min_value=0.1, max_value=0.5, step=0.1)))

    model.add(Dense(units=1))

    model.compile(optimizer='adam', loss='mean_squared_error', metrics=[tf.keras.metrics.MeanAbsoluteError()])

    return model

# Instantiate the tuner
tuner = RandomSearch(
    build_model,
    objective='val_loss',
    max_trials=10,
    executions_per_trial=1,
    directory='my_dir',
    project_name='lstm_hyperparameter_tuning'
)

# Define callback function
current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
csv_logger = CSVLogger('training_logs_{}.csv'.format(current_time))

# Start the tuning process
start_time = time.time()
tuner.search(x_train, y_train, epochs=100, validation_split=0.2, callbacks=[csv_logger])
end_time = time.time()

# Get the best model
best_model = tuner.get_best_models(num_models=1)[0]

# Training time
training_time = end_time - start_time
print("Model training time: {} seconds".format(training_time))
