from flask import Flask, url_for, redirect, json, request, make_response, Response, stream_with_context
import atp_classes, os, gzip, glob

app = Flask(__name__)
config = atp_classes.Config()
app.secret_key = config.get_config()['session_secret']
cache = atp_classes.Cache()
app_db = atp_classes.AppDB()
hive_db = atp_classes.HiveDB()
app_login = atp_classes.AppLogin(app)


def get_attributes_from_db():
    attribute_list = []
    attribute_list_db = app_db.get_collection('attributes')

    for attribute in attribute_list_db:
        attribute_obj = atp_classes.Attribute(attribute)
        attribute_obj.expression_string = attribute_obj.logical_expression.convert_to_string()
        attribute_list.append(attribute_obj)

    return attribute_list


@app.route('/')
@app.route('/<path:path>')
@app_login.required_login
def index(path=None):
    return make_response(open('static/index.html').read())


@app.route('/handleLogin', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        user = atp_classes.User.find_user_by_username(json.loads(request.data)['username'])
        if user and atp_classes.User.validate_login(user.password, json.loads(request.data)['password']):
            user_obj = atp_classes.User(str(user._id), user.username)
            app_login.log_user_in(user_obj)
            return json.dumps({"status": 'success'})
        return json.dumps({"status": 'failed'})
    return redirect(url_for('login_form', next=request.args.get("next")))


@app.route('/login/')
def login_form():
    if app_login.current_user.is_authenticated:
        return redirect(url_for('index'))
    else:
        return make_response(open('static/index.html').read())


@app.route('/isUserAuthenticated/')
def is_user_authenticated():
    if app_login.current_user.is_authenticated:
        return json.dumps({"status": True, "username": app_login.current_user.username})
    else:
        return json.dumps({"status": False})


@app.route('/isUserAdmin/')
def is_user_admin():
    if app_login.current_user.is_authenticated and app_login.current_user.is_admin():
        return json.dumps({"status": True})
    else:
        return json.dumps({"status": False})


@app.route('/logout/')
def logout():
    app_login.log_user_out()
    return redirect('/')


@app.route('/queryHive/', methods=['POST'])
@app_login.required_login
@cache
def query_hive():
    form_chosen_attributes = json.loads(request.data)['chosenAttributes']
    chosen_attributes = []
    query_string = ''

    for dbattribute in get_attributes_from_db():
        for cattribute in form_chosen_attributes:
            if str(dbattribute._id) == cattribute['id']:
                chosen_attributes.append(dbattribute)

    for index, attribute in enumerate(chosen_attributes):
        if config.get_config()['database']["bigData"]['partitionCondition'] != '':
            if not query_string:
                query_string = 'SELECT SUM(CASE WHEN {partitionCondition} THEN 1 ELSE 0 END) total_idp'\
                    .format(partitionCondition=config.get_config()['database']["bigData"]['partitionCondition'])

            query_string += ''',
            SUM(CASE WHEN {expression} AND {partitionCondition} THEN 1 ELSE 0 END) total_{id}'''\
                .format(id=attribute._id, expression=attribute.logical_expression.convert_to_string(),
                        partitionCondition=config.get_config()['database']["bigData"]['partitionCondition'])

            for index2, attribute2 in enumerate(chosen_attributes[(index + 1):]):
                query_string += ''',
                SUM(CASE WHEN ({expression} AND {expression2} AND {partitionCondition}) THEN 1 ELSE 0 END) total_{id1}_{id2}''' \
                    .format(id1=attribute._id, id2=attribute2._id,
                            expression=attribute.logical_expression.convert_to_string(),
                            expression2=attribute2.logical_expression.convert_to_string(),
                            partitionCondition=config.get_config()['database']["bigData"]['partitionCondition'])
        else:
            query_string = '''SELECT COUNT(1) total_idp'''
            query_string += ''',
            SUM(CASE WHEN {expression} THEN 1 ELSE 0 END) total_{id}''' \
                .format(id=attribute._id, expression=attribute.logical_expression.convert_to_string())

            for index2, attribute2 in enumerate(chosen_attributes[(index + 1):]):
                query_string += ''',
                SUM(CASE WHEN ({expression} AND {expression2}) THEN 1 ELSE 0 END) total_{id1}_{id2}''' \
                    .format(id1=attribute._id, id2=attribute2._id,
                            expression=attribute.logical_expression.convert_to_string(),
                            expression2=attribute2.logical_expression.convert_to_string())

    query_string += '''
        FROM {tableName}'''\
        .format(tableName=config.get_config()['database']["bigData"]['tableName'])

    results = hive_db.execute_query(query_string)

    if not isinstance(results, list):
        raise Exception(results)

    return json.dumps(results[0])


@app.route('/queryHive/segments', methods=['POST'])
@app_login.required_login
@cache
def query_hive_segments():
    form_logical_expression = json.loads(request.data)['logical_expression']
    query_logical_expression = atp_classes.LogicalExpression(form_logical_expression)

    if config.get_config()['database']["bigData"]['partitionCondition'] != '':
        query_string = '''SELECT SUM(CASE WHEN {partitionCondition} THEN 1 ELSE 0 END) total_idp,
            SUM(CASE WHEN {expression} AND {partitionCondition} THEN 1 ELSE 0 END) total_seg_idp
            ''' \
            .format(expression=query_logical_expression.convert_to_string(),
                    partitionCondition=config.get_config()['database']["bigData"]['partitionCondition'])

        query_string += '''FROM {tableName}'''\
            .format(tableName=config.get_config()['database']["bigData"]['tableName'])
    else:
        query_string = '''SELECT COUNT(1) total_idp,
            SUM(CASE WHEN {expression} THEN 1 ELSE 0 END) total_seg_idp
            ''' \
            .format(expression=query_logical_expression.convert_to_string())

        query_string += '''FROM {tableName}'''\
            .format(tableName=config.get_config()['database']["bigData"]['tableName'])

    results = hive_db.execute_query(query_string)

    if not isinstance(results, list):
        raise Exception(results)

    return json.dumps(results[0])


@app.route('/queryHive/segments/ids', methods=['POST'])
@app_login.required_login
def query_hive_segments_ids():
    form_logical_expression = json.loads(request.data)['logical_expression']
    query_logical_expression = atp_classes.LogicalExpression(form_logical_expression)

    if config.get_config()['database']["bigData"]['partitionCondition'] != '':
        query_string = '''SELECT id, total_idp, total_seg_idp
        FROM (SELECT SUM(CASE WHEN {partitionCondition} THEN 1 ELSE 0 END) total_idp,
                SUM(CASE WHEN {expression} AND {partitionCondition} THEN 1 ELSE 0 END) total_seg_idp,
                COLLECT_LIST(CASE WHEN {expression} AND {partitionCondition} THEN id ELSE NULL END) id_list
                FROM {tableName}) aggregateTable
        LATERAL VIEW explode(id_list) idTable as id
        ''' \
        .format(expression=query_logical_expression.convert_to_string(),
                tableName=config.get_config()['database']["bigData"]['tableName'],
                partitionCondition=config.get_config()['database']["bigData"]['partitionCondition'])