from app import app, db
from app.models.attachment import Attachment
from app.models.comment import Comment
from app.models.forum import Forum
from app.models.post import Post
from app.models.program import Program
from app.models.thread import Thread
from app.models.topic import Topic
from app.models.user import Member
from app.utils.render import render
from app.utils.check_csrf import check_csrf
from app.forms.forum import CommentEditForm, AnonymousCommentEditForm, TopicEditForm
from app.forms.post import MovePost, SearchThread
from wtforms import BooleanField
from urllib.parse import urlparse
from flask import redirect, url_for, abort, request, flash
from flask_login import login_required, current_user
from sqlalchemy import text

@app.route('/post/editer/<int:postid>', methods=['GET','POST'])
@login_required
def edit_post(postid):
    # TODO: Maybe not safe
    referrer = urlparse(request.args.get('r', default = '/', type = str)).path
    print(referrer)

    p = Post.query.filter_by(id=postid).first_or_404()

    # Check permissions
    if not current_user.can_edit_post(p):
        abort(403)

    if isinstance(p, Comment):
        base = CommentEditForm
        comment = p
    elif isinstance(p, Topic):
        base = TopicEditForm
        comment = p.thread.top_comment
    else:
        abort(404)

    class TheForm(base):
        pass
    for a in comment.attachments:
        setattr(TheForm, f'a{a.id}', BooleanField(f'a{a.id}'))
    setattr(TheForm, 'attachment_list',
        { f'a{a.id}': a for a in comment.attachments })
    form = TheForm()

    if isinstance(p, Topic):
        forums = sorted(Forum.query.all(), key=lambda f: f.url)
        forums = [f for f in forums if current_user.can_post_in_forum(f)]
        form.forum.choices = [(f.url, f"{f.url}: {f.name}") for f in forums]

    if form.validate_on_submit():
        comment.text = form.message.data

        # Remove attachments
        for id, a in form.attachment_list.items():
            if form[id].data:
                a.delete()

        # Add new attachments
        attachments = []
        for file in form.attachments.data:
            if file.filename != "":
                a = Attachment(file, comment)
                attachments.append((a, file))
                db.session.add(a)

        comment.touch()
        db.session.add(comment)

        if isinstance(p, Topic):
            p.title = form.title.data
            f = Forum.query.filter_by(url=form.forum.data).first_or_404()
            if current_user.can_post_in_forum(f):
                p.forum = f
            db.session.merge(p)

        db.session.commit()

        for a, file in attachments:
            a.set_file(file)

        # Determine topic URL now, in case forum was changed
        if isinstance(p, Topic):
            return redirect(url_for('forum_topic', f=p.forum, page=(p,1)))
        else:
            return redirect(referrer)

    # Non-submitted form
    if isinstance(p, Comment):
        form.message.data = p.text
        return render('forum/edit_comment.html', comment=p, form=form)
    elif isinstance(p, Topic):
        form.message.data = p.thread.top_comment.text
        form.title.data = p.title
        form.forum.data = p.forum.url
        return render('forum/edit_topic.html', t=p, form=form)

@app.route('/post/supprimer/<int:postid>', methods=['GET','POST'])
@login_required
@check_csrf
def delete_post(postid):
    next_page = request.referrer
    p = Post.query.filter_by(id=postid).first_or_404()
    xp = -1

    if not current_user.can_delete_post(p):
        abort(403)

    # Users who need to have their trophies updated
    authors = set()

    # When deleting topics, return to forum page
    if isinstance(p, Topic):
        next_page = url_for('forum_page', f=p.forum)
        xp = -2

        for comment in p.thread.comments:
            if isinstance(comment.author, Member):
                comment.author.add_xp(-1)
                db.session.merge(comment.author)
                authors.add(comment.author)

    if isinstance(p.author, Member):
        factor = 3 if request.args.get('penalty') == 'True' else 1
        p.author.add_xp(xp * factor)
        db.session.merge(p.author)
        authors.add(p.author)

    p.delete()
    db.session.commit()

    for author in authors:
        author.update_trophies("new-post")

    return redirect(next_page)

@app.route('/post/entete/<int:postid>', methods=['GET'])
@login_required
@check_csrf
def set_post_topcomment(postid):
    comment = Post.query.filter_by(id=postid).first_or_404()

    if current_user.can_set_topcomment(comment):
        comment.thread.top_comment = comment
        db.session.add(comment.thread)
        db.session.commit()

    return redirect(request.referrer)


@app.route('/post/deplacer/<int:postid>', methods=['GET', 'POST'])
@login_required
def move_post(postid):
    comment = Post.query.filter_by(id=postid).first_or_404()

    if not current_user.can_edit_post(comment):
        abort(403)

    if not isinstance(comment, Comment):
        flash("Vous ne pouvez pas déplacer un message principal", 'error')
        abort(403)

    move_form = MovePost(prefix="move_")
    search_form = SearchThread(prefix="thread_")
    keyword = search_form.name.data if search_form.validate_on_submit() else ""

    # Get 10 last corresponding threads
    # TODO: add support for every MainPost
    req = text("""SELECT thread.id, topic.title FROM thread
        INNER JOIN topic ON topic.thread_id = thread.id
        WHERE lower(topic.title) LIKE lower(:keyword)
        ORDER BY thread.id DESC LIMIT 10""")
    threads = list(db.session.execute(req, {'keyword': '%'+keyword+'%'}))
    move_form.thread.choices = [(t[0], f"{t[1]}") for t in threads]

    if move_form.validate_on_submit():
        thread = Thread.query.get_or_404(move_form.thread.data)
        owner_post = thread.owner_post

        if isinstance(owner_post, Topic):
            t = owner_post
            if not current_user.can_access_forum(t.forum):
                abort(403)
            comment.thread = thread
            db.session.add(comment)
            db.session.commit()
            return redirect(url_for('forum_topic', f=t.forum, page=(t,1)))

    return render('post/move_post.html', comment=comment,
        search_form=search_form, move_form=move_form)
