from __future__ import division
import tensorflow as tf
from os import path
import numpy as np
import pandas as pd
import csv
from sklearn.model_selection import StratifiedShuffleSplit
from time import time
from matplotlib import pyplot as plt
import seaborn as sns
from mylibs.jupyter_notebook_helper import show_graph
from tensorflow.contrib import rnn
from tensorflow.contrib import learn
import shutil
from tensorflow.contrib.learn.python.learn import learn_runner
from mylibs.tf_helper import getDefaultGPUconfig
from sklearn.metrics import r2_score
from mylibs.py_helper import factors
from fastdtw import fastdtw
from scipy.spatial.distance import euclidean
from statsmodels.tsa.stattools import coint
from common import get_or_run_nn
from data_providers.price_history_dummy_seq2seq_data_provider \
    import PriceHistoryDummySeq2SeqDataProvider
from models.price_history_dummy_seq2seq import PriceHistoryDummySeq2Seq

dtype = tf.float32
seed = 16011984
random_state = np.random.RandomState(seed=seed)
config = getDefaultGPUconfig()
%matplotlib inline

"""
Explanation: https://www.youtube.com/watch?v=ElmBrKyMXxs
https://github.com/hans/ipython-notebooks/blob/master/tf/TF%20tutorial.ipynb
https://github.com/ematvey/tensorflow-seq2seq-tutorials
End of explanation
"""


num_epochs = 10

num_features = 1
num_units = 400 #state size

input_len = 60
target_len = 30

batch_size = 47

#trunc_backprop_len = ??

"""
Explanation: Step 0 - hyperparams
vocab_size and max sequence length are the SAME thing
decoder RNN hidden units are usually same size as encoder RNN hidden units in translation but for our case it does not seem really to be a relationship there but we can experiment and find out later, not a priority thing right now
End of explanation
"""


npz_path = '../price_history_03_dp_60to30_from_fixed_len.npz'

dp = PriceHistoryDummySeq2SeqDataProvider(npz_path=npz_path, batch_size=batch_size,
                                          )
dp.inputs.shape, dp.targets.shape

aa, bb, cc = dp.next()
aa.shape, bb.shape, cc.shape

"""
Explanation: Step 1 - collect data (and/or generate them)
End of explanation
"""


model = PriceHistoryDummySeq2Seq(rng=random_state, dtype=dtype, config=config)

graph = model.getGraph(batch_size=batch_size,
                       num_units=num_units,
                       input_len=input_len,
                       target_len=target_len)

#show_graph(graph)

"""
Explanation: Step 2 - Build model
End of explanation
"""


rnn_cell = PriceHistorySeq2Seq.RNN_CELLS.BASIC_RNN
num_epochs = 50
num_epochs, num_units, batch_size

def experiment():
    return model.run(
        npz_path=npz_path,
        epochs=num_epochs,
        batch_size=batch_size,
        num_units=num_units,
        input_len = input_len,
        target_len = target_len,
        rnn_cell=rnn_cell,
    )

dyn_stats = experiment()
#dyn_stats, preds_dict = get_or_run_nn(experiment, filename='003_rnn_slidewin_60to1')

dyn_stats.plotStats()
plt.show()

"""
Explanation: Step 3 training the network
RECALL: baseline is around 4 for huber loss for current problem, anything above 4 should be considered as major errors
Basic RNN cell without predictions - with EOS = 0
End of explanation
"""


rnn_cell = PriceHistorySeq2Seq.RNN_CELLS.BASIC_RNN
num_epochs = 50
num_epochs, num_units, batch_size

def experiment():
    return model.run(
        npz_path=npz_path,
        epochs=num_epochs,
        batch_size=batch_size,
        num_units=num_units,
        input_len = input_len,
        target_len = target_len,
        rnn_cell=rnn_cell,
    )

dyn_stats, preds_dict = get_or_run_nn(experiment, filename='004_rnn_dummy_seq2seq_60to30')

dyn_stats.plotStats()
plt.show()

r2_scores = [r2_score(y_true=dp.targets[ind], y_pred=preds_dict[ind])
            for ind in range(len(dp.targets))]

ind = np.argmin(r2_scores)
ind

reals = dp.targets[ind]
preds = preds_dict[ind]

r2_score(y_true=reals, y_pred=preds)

sns.tsplot(data=dp.inputs[ind].flatten())

fig = plt.figure(figsize=(15,6))
plt.plot(reals, 'b')
plt.plot(preds, 'g')
plt.legend(['reals','preds'])
plt.show()

%%time
dtw_scores = [fastdtw(dp.targets[ind], preds_dict[ind])[0]
             for ind in range(len(dp.targets))]

np.mean(dtw_scores)

coint(preds, reals)

cur_ind = np.random.randint(len(dp.targets))
reals = dp.targets[cur_ind]
preds = preds_dict[cur_ind]
fig = plt.figure(figsize=(15,6))
plt.plot(reals, 'b')
plt.plot(preds, 'g')
plt.legend(['reals','preds'])
plt.show()

"""
Explanation: Conclusion
//...
Basic RNN cell - with EOS = 0
End of explanation
"""


rnn_cell = PriceHistorySeq2Seq.RNN_CELLS.GRU
num_epochs = 20
num_epochs, num_units, batch_size

def experiment():
    return model.run(
        npz_path=npz_path,
        epochs=num_epochs,
        batch_size=batch_size,
        num_units=num_units,
        input_len = input_len,
        target_len = target_len,
        rnn_cell=rnn_cell,
    )

#dyn_stats = experiment()
dyn_stats, preds_dict = get_or_run_nn(experiment, filename='004_rnn_dummy_seq2seq_gru_60to30')

dyn_stats.plotStats()
plt.show()

r2_scores = [r2_score(y_true=dp.targets[ind], y_pred=preds_dict[ind])
            for ind in range(len(dp.targets))]

ind = np.argmin(r2_scores)
ind

reals = dp.targets[ind]
preds = preds_dict[ind]

r2_score(y_true=reals, y_pred=preds)

sns.tsplot(data=dp.inputs[ind].flatten())

fig = plt.figure(figsize=(15,6))
plt.plot(reals, 'b')
plt.plot(preds, 'g')
plt.legend(['reals','preds'])
plt.show()

%%time
dtw_scores = [fastdtw(dp.targets[ind], preds_dict[ind])[0]
             for ind in range(len(dp.targets))]

np.mean(dtw_scores)

coint(preds, reals)

cur_ind = np.random.randint(len(dp.targets))
reals = dp.targets[cur_ind]
preds = preds_dict[cur_ind]
fig = plt.figure(figsize=(15,6))
plt.plot(reals, 'b')
plt.plot(preds, 'g')
plt.legend(['reals','preds'])
plt.show()

"""
Explanation: Conclusion
They are obviously shifted...
GRU cell - with EOS = 0
End of explanation
"""


