from flask_login import current_user
from flask import request, redirect, url_for, abort, flash

from app import app, db
from config import V5Config
from app.utils.render import render
from app.forms.forum import TopicCreationForm, AnonymousTopicCreationForm
from app.models.forum import Forum
from app.models.topic import Topic
from app.models.thread import Thread
from app.models.comment import Comment
from app.models.user import Guest
from app.models.attachment import Attachment


@app.route('/forum/')
def forum_index():
    return render('/forum/index.html')

@app.route('/forum/<forum:f>/', methods=['GET', 'POST'])
@app.route('/forum/<forum:f>/p/<int:page>', methods=['GET', 'POST'])
def forum_page(f, page=1):
    if not f.is_default_accessible() and not (
        current_user.is_authenticated and current_user.can_access_forum(f)):
        abort(403)

    if current_user.is_authenticated:
        form = TopicCreationForm()
    else:
        form = AnonymousTopicCreationForm()

    if form.validate_on_submit() and (
        (V5Config.ENABLE_GUEST_POST and f.is_default_postable()) or \
        (current_user.is_authenticated and current_user.can_post_in_forum(f))):

        # Manage author
        if current_user.is_authenticated:
            author = current_user
        else:
            author = Guest(form.pseudo.data)
            db.session.add(author)

        # First create the thread, then the comment, then the topic
        th = Thread()
        db.session.add(th)
        db.session.commit()

        c = Comment(author, form.message.data, th)
        db.session.add(c)
        db.session.commit()

        th.set_top_comment(c)
        db.session.merge(th)

        t = Topic(f, author, form.title.data, th)
        db.session.add(t)
        db.session.commit()

        # Manage files
        attachments = []
        for file in form.attachments.data:
            if file.filename != "":
                a = Attachment(file, c)
                attachments.append((a, file))
                db.session.add(a)
        db.session.commit()
        for a, file in attachments:
            a.set_file(file)

        # Update member's xp and trophies
        if current_user.is_authenticated:
            current_user.add_xp(2)  # 2 points for a topic
            current_user.update_trophies('new-post')

        flash('Le sujet a bien été créé', 'ok')
        return redirect(url_for('forum_topic', f=f, page=(t,1)))

    # Paginate topic pages
    # TODO: order by last comment date
    topics = f.topics.order_by(Topic.date_created.desc()).paginate(
        page, Forum.TOPICS_PER_PAGE, True)

    # Count comments; this direct request avoids performing one request for
    # each topic.thread.comments.count() in the view, which the database
    # doesn't really appreciate performance-wise.
    selection = " OR ".join(f"thread_id={t.thread.id}" for t in topics.items)
    selection = "WHERE " + selection if selection else ""

    comment_counts = db.session.execute(f"""
        SELECT thread_id, COUNT(*) FROM comment {selection}
        GROUP BY thread_id
    """)
    comment_counts = dict(list(comment_counts))

    return render('/forum/forum.html', f=f, topics=topics, form=form,
        comment_counts=comment_counts)
