from flask import Flask, request, render_template, send_from_directory, abort, redirect, session
from flask_sqlalchemy import SQLAlchemy
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
import re
import random
from datetime import datetime
from dateutil.tz import tzlocal
import html2text
from config_fudan  import C

app = Flask(__name__)
app.config.from_object('config_fudan.C')
app.secret_key = C.session_key

limiter = Limiter(
    app,
    key_func=get_remote_address,
    default_limits=["50 / minute"],
)

db = SQLAlchemy(app)

class Candidate(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.String(4000))
    private = db.Column(db.String(1000))
    time = db.Column(db.DateTime)
    likeNum = db.Column(db.Integer, default=0)

    # always increment 1 for the id of a new record
    __table_args__ = { 'sqlite_autoincrement': True }

class Like(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    cid = db.Column(db.Integer) # (member) id of class Candidate
    uid = db.Column(db.Integer) # id of user

db.create_all()

@app.route('/img/<path:path>')
def send_img(path):
    return send_from_directory('static/img', path)

@app.route('/ordinary/set_session')
@limiter.limit("2 / hour; 1 / 5 minute")
def set_session():
    if 'uid' not in session:
        session['uid'] = random.randint(0, 2000000000)
        session.permanent = True
    return redirect('.')

@app.route('/ordinary/')
def can_list():
    key = request.args.get('key')
    sort_by = request.args.get('sort_by', 'time')

    if 'uid' not in session:
        return redirect('set_session')
    uid = session['uid']

    q = Candidate.query
    q = q.order_by(db.desc('likeNum')) if sort_by=='likeNum' else q.order_by(db.desc('id'))
    pag = q.paginate(max_per_page=100)

    def check_like(c):
        c.liked = 'liked' if Like.query.filter_by(uid=uid, cid=c.id).count() else 'like'
        return c

    pag.items = map(check_like,  pag.items)

    vs = [{
        'name': name,
        'ques': ques,
        'hint': hint
        } for name, ques, hint, ans in C.verify
    ]

    return render_template('list.html', pagination=pag, vs=vs, showPrivate=(key==C.key), sort_by=sort_by, key=key, text1=C.text1, text2=C.text2)

@app.route('/ordinary/new', methods=['POST'])
@limiter.limit("5 / hour; 1 / 2 second")
def new_one():

    content = request.form.get('text')
    private = request.form.get('privateText')

    for name, ques, hint, ans in C.verify:
        if request.form.get(name) != ans:
            return '''<html>
            <head>
            <meta charset='UTF-8'>
            <meta name='viewport' content='width=device-width initial-scale=1'>
            <title>错误</title>
            </head>
            <body>
            <h1>验证问题回答错误</h1>
            <a href="##" onclick="window.history.back()">回退</a>
            </body>
            </html>
        ''', 401

    if not content or len(content)>4000: abort(422)
    if    private and len(private)>1000: abort(422)

    if not Candidate.query.filter_by(content=content).first():
        c = Candidate(
                content=content,
                private=private,
                time=datetime.now()
            )
        db.session.add(c)
        db.session.commit()

    return redirect(".")

@limiter.limit("100 / hour")
@app.route('/ordinary/<int:id>/like', methods=['POST'])
def like(id):
    c = Candidate.query.get(id)
    if not c:
        abort(404)

    uid = session['uid']
    if not uid: abort(401)
    if Like.query.filter_by(uid=uid, cid=id).first():
        return '点赞过了', 403

    l = Like(uid=uid, cid=id)
    c.likeNum += 1
    db.session.add(l)
    db.session.commit()

    return str(c.likeNum)


if __name__ == '__main__':
    app.run(debug=True)

