import functools
import ldap
import flask
import urllib

from webapp import app, context, config, ldaputils

bp = flask.Blueprint('auth', __name__)

def login_required(f):
    @functools.wraps(f)
    def func(*a, **kw):
        conn = context.get_connection()
        if not conn:
            flask.session.clear()
            flask.flash('You must log in to continue', category='warning')
            return flask.redirect('/login?' + urllib.parse.urlencode({'goto': flask.request.path}))
        return f(*a, **kw)
    return func

def req_to_ctx():
    return dict(flask.request.form.items())

@bp.route('/login', methods=["GET"])
def login_form():
    return flask.render_template('login.html', **req_to_ctx())

def _connect_to_ldap(dn, password):
    try:
        return app.connections.bind(dn, password)
    except ldap.LDAPError as error_message:
        print("Could not connect to server:", error_message)
        return None

@bp.route('/login', methods=["POST"])
def login_action():
    # LDAP usernames/DNs are case-insensitive, so we normalize them just in
    # case,
    username = flask.request.form.get("username", "").lower()
    password = flask.request.form.get("password", "")
    goto = flask.request.values.get("goto", "/")
    dn = ldaputils.user_dn(username)

    conn = _connect_to_ldap(dn, password)
    if conn:
        # Now that we have logged in, we can retrieve the 'real' username (which
        # might be cased differently from the login name).
        res = conn.search_s(dn, ldap.SCOPE_SUBTREE)
        for (k, vs) in res[0][1].items():
            if k == 'uid':
                username = vs[0].decode()

        # Check if user belongs to admin group
        is_admin = bool(conn.search_s(dn, ldap.SCOPE_SUBTREE, ldaputils.member_of_any(config.ldap_admin_groups)))

        flask.session["username"] = username
        flask.session['dn'] = dn
        flask.session['is_admin'] = is_admin
        context.refresh_profile()
        return flask.redirect(goto)
    else:
        flask.flash("Invalid credentials.", category='danger')
        return login_form()

@bp.route('/logout')
@login_required
def logout_action():
    app.connections.unbind(flask.session['dn'])
    flask.session.clear()
    return flask.redirect('/')
