"""
model predicting if an airbnb listing is fair or not
"""
#%matplotlib inline
#%config InlineBackend.figure_format = 'retina'

import numpy as np
import pandas as pd
#import seaborn as sns
import os
import sys
#import pylab

from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.cross_validation import cross_val_score, train_test_split
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.linear_model import Ridge, RidgeCV, Lasso
from sklearn.ensemble import RandomForestRegressor
from sklearn import metrics
import xgboost as xgb

from sklearn.externals import joblib
from sqlalchemy import create_engine
from sqlalchemy_utils import database_exists, create_database
import psycopg2

from keras.models import Sequential
from keras.layers import Dense, Dropout


home_folder = os.environ["home_folder"]
sys.path.append(os.path.join(home_folder, "airbnb_app/airbnb/web_app/flaskexample/"))
import airbnb_pipeline

def rmse(y_true, y_pred):
    return(np.sqrt(metrics.mean_squared_error(y_true, y_pred)))

def one_hot_encode_amenities(train):
    """
    amenities comes a weird form, this function one hot encodes them
    """
    train.amenities = train.amenities.str.replace("[{}]", "")
    amenities =  ",".join(train.amenities)
    amenities = np.unique(amenities.split(","))
    amenities_dict = dict(enumerate(amenities))

    train.amenities = train.amenities.str.split(",")
    amenity_ohe = [[ame in amenity_list for ame in amenities]
                                        for amenity_list in train.amenities]
    amenity_ohe = 1*(np.array(amenity_ohe))

    return amenity_ohe

def extract_features_price_model(train,add_BOW = False):
    """
    encodes categorical variables, concatenates with numeric and amenities
    optionally add a sparse bag of words feature matrix
    """


    scale = StandardScaler()

    #get dummies one hot encodes categorical feats and leaves numeric feats alone:
    X_num = pd.get_dummies(train_num_cat)
    X_num = scale.fit_transform(X_num)
    amenity_ohe = one_hot_encode_amenities(train)

    #whether to add BOW to final features - helps marginally:

    if add_BOW == True:
        train_text = train[["name", "summary", "amenities"]]
        #keep min_df large here ~ 300 otherwise detrimental to model
        vect = TfidfVectorizer(stop_words = "english", min_df = 300)
        X_text = vect.fit_transform(train["summary"])
        X_full = np.hstack((X_num, amenity_ohe, X_text.toarray()))
    else:
        X_full = np.hstack((X_num, amenity_ohe))

    return X_full


def validate_model(model, data, y):
    """
    splits the data, fits the model and returns the rmse on val set
    """
    #TODO: make it return MAE or R^2 here
    X_tr, X_val, y_tr, y_val = train_test_split(data, y, random_state = 3)
    preds = model.fit(X_tr, y_tr).predict(X_val)
    return rmse(preds, y_val)


#~~~~~~~~~~~~~~~
#POSTGRES:
#~~~~~~~~~~~~~~


home_folder = os.environ["home_folder"]
dbname = os.environ["dbname"]
username = os.environ["username"]

if sys.platform == "linux":
    password = os.environ["password"]

if sys.platform == "linux":
    connect_str = "dbname='%s' user='%s' host='localhost' password='%s'"%(dbname,username,password)
    con = psycopg2.connect(connect_str)
    engine = create_engine('postgres://%s@localhost/%s'%(username,dbname, password))
else:
    con = psycopg2.connect(database = dbname, user = username)
    engine = create_engine('postgres://%s@localhost/%s'%(username,dbname))