from flask import Flask, render_template, request, redirect, url_for
import sqlalchemy as dbs
import pandas as pd
import urllib.parse
from configparser import ConfigParser
import logging
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, login_required, login_user, logout_user, current_user
from flask_bcrypt import Bcrypt



logging.basicConfig(filename='/var/www/html/annex_survey/survey/logs/app.log',
                    filemode='a',
                    format='%(asctime)s %(name)s %(levelname)s %(message)s',
                    level=logging.INFO)

config_object = ConfigParser()
config_object.read(".config.ini")

app = Flask(__name__)

# get info
dbinfo = config_object['db']
app.config['SECRET_KEY'] = config_object['secret']
app.config["SQLALCHEMY_DATABASE_URI"] = 'mysql+pymysql://' + str(dbinfo["user"]) + ':' + urllib.parse.quote(str(dbinfo["password"])) + '@' + str(dbinfo['host']) + ':' + str(dbinfo["port"]) + '/' + str(dbinfo["db"])
db = SQLAlchemy(app)
login_manager = LoginManager(app)
bcrypt = Bcrypt()


class User(db.Model):
    """An admin user capable of viewing reports.

    :param str email: email address of user
    :param str password: encrypted password for the user

    """
    __tablename__ = 'users'

    email = db.Column(db.String, primary_key=True)
    password = db.Column(db.String)
    authenticated = db.Column(db.Boolean, default=False)

    def is_active(self):
        """True, as all users are active."""
        return True

    def get_id(self):
        """Return the email address to satisfy Flask-Login's requirements."""
        return self.email

    def is_authenticated(self):
        """Return True if the user is authenticated."""
        return self.authenticated

    def is_anonymous(self):
        """False, as anonymous users aren't supported."""
        return False




@login_manager.user_loader
def user_loader(user_id):
    """Given *user_id*, return the associated User object.

    :param unicode user_id: user_id (email) user to retrieve

    """
    return User.query.get(user_id)

@app.route('/login')
def initial_login():
    return redirect(url_for('login'))


@app.route("/admin", methods=["GET", "POST"])
def login():
    """For GET requests, display the login form. 
    For POSTS, login the current user by processing the form.

    """
    if request.method == 'POST':
        email = request.form['email']
        password = request.form['password']
        logging.info(f"[email:{email}] [password:{password}]")
        current_user = User.query.get(email)
        logging.info(current_user)
        if current_user:
            status = bcrypt.check_password_hash(current_user.password, password)

            if status:
                current_user.authenticated = True
                db.session.add(current_user)
                db.session.commit()
                login_user(current_user)
                return redirect(url_for("adminDashboard"))
    return render_template("login.html")


@app.route("/logout", methods=["GET"])
@login_required
def logout():
    """Logout the current user."""
    user = current_user
    user.authenticated = False
    db.session.add(user)
    db.session.commit()
    logout_user()
    return render_template("login.html")


@app.route("/admin/dashboard", methods=["GET", "POST"])
@login_required
def adminDashboard():
    """Admin View"""
    cnx = dbs.create_engine('mysql+pymysql://' + str(dbinfo["user"]) + ':' + urllib.parse.quote(str(dbinfo["password"])) + '@' + str(dbinfo['host']) + ':' + str(dbinfo["port"]) + '/' + str(dbinfo["db"]))
    conn = cnx.connect().execution_options(stream_results=True)

    df = pd.read_sql('select * from collections order by created_at desc', conn)
    records = df.to_dict(orient='records')
    conn.close()

    return render_template("admin.html", details=records)



@app.route('/', methods=['GET', 'POST'])
def annex():
    if request.method == 'POST':
        try:
            dit = request.form.to_dict()
            dit_df = pd.DataFrame(dit, index=[0])
            dit_df.fillna('', inplace=True)
            dit_df['num_children'] = dit_df['num_children'].astype('int')
            dit_df.set_index('fullname', inplace=True)

            cnx = dbs.create_engine('mysql+pymysql://' + str(dbinfo["user"]) + ':' + urllib.parse.quote(str(dbinfo["password"])) + '@' + str(dbinfo['host']) + ':' + str(dbinfo["port"]) + '/' + str(dbinfo["db"]))
            conn = cnx.connect()

            dit_df.to_sql('collections', con=conn, if_exists='append')
            conn.close()
    
            return render_template("success.html")
        except Exception as e:
            logging.info(f'Failed with error {e}')
            return render_template("failure.html")
    else:

        cnx = dbs.create_engine('mysql+pymysql://' + str(dbinfo["user"]) + ':' + urllib.parse.quote(str(dbinfo["password"])) + '@' + str(dbinfo['host']) + ':' + str(dbinfo["port"]) + '/' + str(dbinfo["db"]))
        conn = cnx.connect()

        df_1 = pd.read_sql('select polling_station from polling_stations where polling_station is not null', conn)
        df_1 = df_1[df_1 != None]
        stations = df_1.to_dict(orient='records')
        df_1 = pd.read_sql('select distinct(electoral_area) from polling_stations where electoral_area is not null', conn)
        df_1 = df_1[df_1 != None]
        electoral_area = df_1.to_dict(orient='records')


        conn.close()
        
        return render_template(
            "annex_form.html", stations=stations, electoral_area=electoral_area
        )


if __name__ == '__main__':
    app.run(host='0.0.0.0')