import json
import plotly
import pandas as pd

import re
import nltk
nltk.download(['punkt', 'wordnet'])
from nltk.tokenize import word_tokenize
from nltk.stem import WordNetLemmatizer

from flask import Flask
from flask import render_template, request, jsonify
from plotly.graph_objs import Bar

# The import is changed after sklearn 0.23
#from sklearn.externals import joblib
import joblib 

from sqlalchemy import create_engine
import sys

# Import a custom library from specific path
sys.path.append('../share') 
import share_lib


app = Flask(__name__)


def extract_category_names(df):
    """Extracts multiple category names of target variables from input dataframe.

    Args:
    df: Input dataframe containing target variables

    Returns:
    Target variable (column) names in a string array
    """

    # Define the filtering columns not belong to target variable column names
    filter_cols = ['index', 'id', 'message', 'original', 'genre']
    
    # Find all columns which do not belong to the filtering columns
    category_names = []
    for col in df.columns.values:
        if col not in filter_cols:
            category_names.append(str(col))
            
    return category_names


def tokenize(text):
    """Text processing functions including normalization, word tokenization, lemmatization.

    Args:
    text : A sentence of text.

    Returns:
    Tokenized words in a string array.
    """
    
    # Punctuation removal
    text = re.sub(r"[^a-zA-Z0-9]", " ", text)
    
    # Word tokenization
    tokens = word_tokenize(text)
    lemmatizer = WordNetLemmatizer()

    clean_tokens = []
    for tok in tokens:
        clean_tok = lemmatizer.lemmatize(tok).lower().strip() #Case normalization and lemmatization
        clean_tokens.append(clean_tok)

    return clean_tokens


# load data
engine = create_engine('sqlite:///../data/DisasterResponse.db')
df = pd.read_sql_table('Message', engine)

# load model
model = joblib.load("../models/classifier.pkl")

# index webpage displays cool visuals and receives user input text for model
@app.route('/')
@app.route('/index')
def index():
    
    # extract data needed for visuals
    # TODO: Below is an example - modify to extract data for your own visuals
    genre_counts = df.groupby('genre').count()['message']
    genre_names = list(genre_counts.index)
    
    category_names = extract_category_names(df)
    category_counts = df[ category_names ].sum()

    # create visuals
    # TODO: Below is an example - modify to create your own visuals
    graphs = [
        {
            'data': [
                Bar(
                    x=genre_names,
                    y=genre_counts
                )
            ],

            'layout': {
                'title': 'Distribution of Message Genres',
                'yaxis': {
                    'title': "Count"
                },
                'xaxis': {
                    'title': "Genre"
                }
            }
        }, 
        {
            'data': [
                Bar(
                    x=category_names,
                    y=category_counts
                )
            ],

            'layout': {
                'title': 'Distribution of Message Category',
                'yaxis': {
                    'title': "Count"
                },
                'xaxis': {
                    'title': "Category"
                }
            }
        }
    ]
    
    # encode plotly graphs in JSON
    ids = ["graph-{}".format(i) for i, _ in enumerate(graphs)]
    graphJSON = json.dumps(graphs, cls=plotly.utils.PlotlyJSONEncoder)
    
    # render web page with plotly graphs
    return render_template('master.html', ids=ids, graphJSON=graphJSON)


# web page that handles user query and displays model results
@app.route('/go')
def go():
    # save user input in query
    query = request.args.get('query', '') 

    # use model to predict classification for query
    classification_labels = model.predict([query])[0]
    classification_results = dict(zip(df.columns[4:], classification_labels))

    # This will render the go.html Please see that file. 
    return render_template(
        'go.html',
        query=query,
        classification_result=classification_results
    )


def main():
    app.run(host='0.0.0.0', port=3001, debug=True)


if __name__ == '__main__':
    main()