import argparse
import numpy
import pandas as pd
import os
from keras import backend as K
from keras.models import Sequential
from keras.layers import Dense
from keras.models import model_from_json
from ngram_classifier import NGramClassifier
from sklearn.metrics import precision_recall_fscore_support

CLASS_WEIGHTS = [
    ("num_days", 0.997821848), 
    ("statuses_per_day", 1.065570851),
    ("followers_per_day", 1.021055002),
    ("following_per_day", 1.122703153),
    ("desc_len_terms", 1.171072307),
    ("num_list_items", 1.017727903),
    ("num_hashtags", 0.889418197),
    ("url_count", 1.018365516)
]

def get_input_vector(row, classifier):
    '''
    (classifier): p_good
    (classifier): p_bot
    num_days
    statuses_per_day
    followers_per_day
    following_per_day
    desc_len_terms
    num_list_items
    num_hashtags
    url_count
    '''
    class_probs = classifier.classify_text(str(row["user_profile_description"]))
    ret = [ class_probs["good"], class_probs["bot"]]
    for label, weight in CLASS_WEIGHTS:
        ret.append(float(row[label]) * weight)
    return ret


def get_training_output(row):
    class_label = str(row["class_value"])
    return 0.0 if class_label == "good" else 1.0


def recall_m(y_true, y_pred):
        true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
        possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))
        recall = true_positives / (possible_positives + K.epsilon())
        return recall


def precision_m(y_true, y_pred):
        true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
        predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1)))
        precision = true_positives / (predicted_positives + K.epsilon())
        return precision


def f1_m(y_true, y_pred):
    precision = precision_m(y_true, y_pred)
    recall = recall_m(y_true, y_pred)
    return 2*((precision*recall)/(precision+recall+K.epsilon()))


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("-i", "--input", help="test input csv file")
    parser.add_argument("-m", "--model", help="ngram model file")
    parser.add_argument("-n", "--nnetmodel", help="NNet model file")
    args = parser.parse_args()

    if not args.input:
        raise "missing input file"
    if not args.model:
        raise "missing ngram model file"
    if not args.nnetmodel:
        raise "missing nnet model file"

    classifier = NGramClassifier(model_path=args.model)

    with open(args.nnetmodel, 'r') as json_file:
        loaded_model_json = json_file.read()
        nnet = model_from_json(loaded_model_json)
    nnet.load_weights(f'{args.nnetmodel}.h5')
    nnet.compile(loss='binary_crossentropy', optimizer='adam', metrics=['acc',f1_m,precision_m, recall_m])
    
    df_test = pd.read_csv(args.input, keep_default_na=False)
    targets_x = []
    targets_y = []
    predictions = []
    for index, row in df_test.iterrows():
        input_vector = get_input_vector(row, classifier)
        targets_x.append(input_vector)
        targets_y.append(get_training_output(row))
    loss, accuracy, f1_score, precision, recall = nnet.evaluate(numpy.array(targets_x), numpy.array(targets_y), verbose=0)

    print(f'loss: {loss}, acc: {accuracy}, prec: {precision}, recall: {recall}, f1: {f1_score}')

pandas.read_csv