from flask import request, flash, redirect, url_for
from app.utils.priv_required import priv_required
from flask_wtf import FlaskForm
from wtforms import SubmitField
from app.models.users import Member, Group, GroupPrivilege
from app.models.privs import SpecialPrivilege
from app.forms.account import AdminUpdateAccountForm, AdminDeleteAccountForm
from app.utils.render import render
from app import app, db
import yaml
import os


@app.route('/admin', methods=['GET', 'POST'])
@priv_required('access-admin-panel')
def adm():
    return render('admin/index.html')


@app.route('/admin/groups', methods=['GET', 'POST'])
@priv_required('access-admin-panel')
def adm_groups():
    class GroupRegenerationForm(FlaskForm):
        submit = SubmitField(
            'Régénérer les groupes, privilèges, et comptes communs')

    form = GroupRegenerationForm()
    if form.validate_on_submit():
        # Clean up groups
        for g in Group.query.all():
            g.delete()

        # Create base groups
        groups = []
        with open(os.path.join(app.root_path, "data", "groups.yaml")) as fp:
            groups = yaml.load(fp.read())

        for g in groups:
            g["obj"] = Group(g["name"], g["css"], g["descr"])
            db.session.add(g["obj"])
        db.session.commit()

        for g in groups:
            for priv in g.get("privs", "").split():
                db.session.add(GroupPrivilege(g["obj"], priv))
        db.session.commit()

        # Clean up test members
        for name in "PlanèteCasio GLaDOS".split():
            m = Member.query.filter_by(name=name).first()
            if m is not None:
                m.delete()

        # Create template members

        def addgroup(member, group):
            g = Group.query.filter_by(name=group).first()
            if g is not None:
                member.groups.append(g)

        m = Member('PlanèteCasio', 'contact@planet-casio.com', 'v5-forever')
        addgroup(m, "Compte communautaire")
        db.session.add(m)

        m = Member('GLaDOS', 'glados@aperture.science', 'v5-forever')
        m.xp = 1337
        addgroup(m, "Robot")
        db.session.add(m)
        db.session.commit()

        db.session.add(SpecialPrivilege(m, "edit-posts"))
        db.session.add(SpecialPrivilege(m, "shoutbox-ban"))

        db.session.commit()

    users = Member.query.all()
    groups = Group.query.all()

    return render('admin/groups_privileges.html', users=users, groups=groups,
        form=form)


@app.route('/admin/edit-account/<user_id>', methods=['GET', 'POST'])
@priv_required('edit-account')
def adm_edit_account(user_id):
    user = Member.query.filter_by(id=user_id).first_or_404()

    form = AdminUpdateAccountForm()
    if request.method == "POST":
        if form.validate_on_submit():
            if form.avatar.data:
                f = form.avatar.data
                f.save("./app/static/" + user.avatar)

            newname = form.username.data
            names = list(Member.query.filter(Member.id != user.id).values(Member.name))
            if newname in names:
                raise Exception(f'{newname} is not available')
            user.update(
                name=form.username.data or None,
                email=form.email.data or None,
                password=form.password.data or None,
                birthday=form.birthday.data,
                signature=form.signature.data,
                bio=form.biography.data,
                newsletter=form.newsletter.data,
                xp=form.xp.data or None,
            )
            db.session.merge(user)
            db.session.commit()
            # TODO: send an email to member saying his account has been modified
            flash('Modifications effectuées', 'ok')
        else:
            flash('Erreur lors de la modification', 'error')

    return render('admin/edit_account.html', user=user, form=form)


@app.route('/admin/edit-account/<user_id>/delete', methods=['GET', 'POST'])
@priv_required('delete-account')
def adm_delete_account(user_id):
    user = Member.query.filter_by(id=user_id).first_or_404()

    # Note: A user deleting their own account will be disconnected.

    # TODO: Add an overview of what will be deleted.
    # * How many posts will be turned into guest posts
    # * Option: purely delete the posts in question
    # * How many PMs will be deleted (can't unassign PMs)
    # * etc.
    del_form = AdminDeleteAccountForm()
    if request.method == "POST":
        if del_form.validate_on_submit():
            user.delete()
            flash('Compte supprimé', 'ok')
            return redirect(url_for('adm'))
        else:
            flash('Erreur lors de la suppression du compte', 'error')
            del_form.delete.data = False  # Force to tick to delete the account
    return render('admin/delete_account.html', user=user, del_form=del_form)
