from flask import render_template, Blueprint, request, session, redirect, \
                  url_for, flash, current_app, make_response
from flask_login import login_user, login_required, logout_user, current_user
from datetime import datetime
from ..forms import RegisterForm, LoginForm, ChangeEmailForm, PostForm, \
                    ResetPasswordRequestForm, ResetPasswordForm, CommentForm
from ..models import db, User, Post, Permission, Comment
from ..email import send_email

front = Blueprint('front', __name__)

@front.before_app_request
def if_user_is_confirmed():
    if current_user.is_authenticated:
        current_user.ping()
        if not current_user.confirmed and request.blueprint != 'front':
            return redirect(url_for('front.unconfirmed'))

@front.route('/unconfirmed')
@login_required
def unconfirmed():
    if current_user.confirmed:
        return redirect(url_for('.index'))
    return render_template('user/confirm.html')

@login_required
@front.route('/confirm')
def resend_confirm_email():
    token = current_user.generate_confirm_token()
    send_email(current_user, current_user.email, 'confirm', token)
    flash('A new confirmation email has been sent to you by email.', 'info')
    return redirect(url_for('.index'))

@front.route('/', methods=['get', 'post'])
def index():
    form = PostForm()
    show_followed = False
    if current_user.is_authenticated:
        show_followed = request.cookies.get('show_followed')
        if current_user.has_permission(Permission.WRITE) \
            and form.validate_on_submit():
            # current_user 由 Flask-Login 提供，和所有上下文环境变量一样
            # 也是通过线程的代理对象实现，这个对象的表现类似用户对象
            # 但实际上却是一个轻度包装，它包含了真正的用户对象
            # 数据库需要真正的用户对象，因此需要调用 _get_current_object 方法
            post = Post(body=form.body.data, 
                        author=current_user._get_current_object())
            db.session.add(post)
            db.session.commit()
            return redirect(url_for('.index'))
    if show_followed:
        query = current_user.followed_posts
    else:
        query = Post.query
    page = request.args.get('page', default=1, type=int)
    pagination = query.order_by(Post.timestamp.desc()).paginate(
            page, per_page=current_app.config.get('POST_PER_PAGE'),
            error_out=False)
    posts = pagination.items
    name = session.get('name') or 'Stranger'
    return render_template('index.html', name=name, form=form, posts=posts,
           Permission=Permission, pagination=pagination,
           show_followed=show_followed)

@front.route('/all')
@login_required
def show_all():
    resp = make_response(redirect(url_for('.index')))
    resp.set_cookie('show_followed', '', max_age=24*3600)
    return resp

@front.route('/followed')
@login_required
def show_followed():
    resp = make_response(redirect(url_for('.index')))
    resp.set_cookie('show_followed', '1', max_age=24*3600)
    return resp

@front.route('/register', methods=['get', 'post'])
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        form.create_user()
        session['name'] = form.name.data
        flash('欢迎新用户：{}'.format(form.name.data), 'info')
        return redirect(url_for('.login'))
    return render_template('register.html', form=form)

@front.route('/confirm/<token>')
@login_required
def confirm(token):
    if current_user.confirmed:
        flash('The confirmation link is invalid or has expired.', 'info')
    elif current_user.confirm(token.encode()):
        flash('You have confirmed your account. Thanks!', 'success')
    return redirect('/')

@front.route('/reset_password', methods=['get', 'post'])
def reset_password_request():
    if not current_user.is_anonymous:
        return redirect(url_for('.index'))
    form = ResetPasswordRequestForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data).first()
        token = user.generate_reset_password_token()
        send_email(user, user.email, 'reset_password', token)
        flash('An email with instructions to reset your password has been'
              'sent to you.', 'info')
        return redirect(url_for('.login'))
    return render_template('user/reset_password.html', form=form)

@front.route('/reset_password/<token>', methods=['get', 'post'])
def reset_password(token):
    if not current_user.is_anonymous:
        return redirect(url_for('.index'))
    form = ResetPasswordForm()
    if form.validate_on_submit():
        if User.reset_password_confirm(token, form.password.data):
            flash('Your password has been updated.', 'success')
            return redirect(url_for('.login'))
        flash('你这个修改密码的链接有问题', 'danger')
        return redirect(url_for('.index'))
    return render_template('user/reset_password.html', form=form)


@front.route('/login', methods=['get', 'post'])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(name=form.name_or_email.data).first()
        if not user:
            user = User.query.filter_by(email=form.name_or_email.data).first()
        login_user(user, form.remember_me.data)
        session['name'] = form.name_or_email.data
        flash('您已登录成功', 'success')
        user.ping()
        return redirect('/')
    return render_template('login.html', form=form)

@login_required
@front.route('/logout')
def logout():
    logout_user()
    session['name'] = None
    flash('您已退出登录', 'info')
    return redirect('/')

@front.route('/post/<int:post_id>', methods=['get', 'post'])
def post_index(post_id):
    post = Post.query.get_or_404(post_id)
    form = CommentForm()
    if form.validate_on_submit():
        comment = Comment(body=form.body.data,
                          post=post,
                          author=current_user._get_current_object())
        db.session.add(comment)
        db.session.commit()
        flash('Your comment has been published.', 'success')
        # 重定向到博客评论的第一页（这里可能需要 TODO
        return redirect(url_for('.post_index', post_id=post.id, page=1))
    page = request.args.get('page', type=int, default=1)
    pagination = post.comments.order_by(Comment.timestamp.asc()).paginate(
        page=page, per_page=current_app.config.get('COMMENT_PER_PAGE'),
        error_out=False)
    comments = pagination.items
    return render_template('post_index.html', posts=[post], form=form,
                           comments=comments, pagination=pagination,
                           Permission=Permission)

@front.route('/edit/post/<int:id>', methods=['get', 'post'])
@login_required
def edit_post(id):
    post = Post.query.get_or_404(id)
    if current_user != post.author \
            or not post.author.has_permission(Permission.WRITE):
        abort(403)
    form = PostForm(obj=post)
    if form.validate_on_submit():
        post.body = form.body.data
        db.session.add(post)
        db.session.commit()
        flash('博客已更新', 'success')
        return redirect(url_for('user.index', user_id=post.author.id))
    return render_template('edit_posts.html', form=form)
