from flask import Flask, abort, jsonify, url_for, render_template, g, request
from flask.json import JSONEncoder
from flask_sqlalchemy import SQLAlchemy
from flask_httpauth import HTTPBasicAuth
import decimal, re, json
from passlib.apps import custom_app_context as pwd_context
from itsdangerous import (TimedJSONWebSignatureSerializer as Serializer, BadSignature, SignatureExpired)

app = Flask(__name__)
#Configuration for Database ORM
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://groceryadmin:VKov2q3XTtqj6w9o@localhost/groceryapp'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)

app.config['SECRET_KEY'] = 'geunyeorang cheoeum daehoa sijag hajamaja'
auth = HTTPBasicAuth()


#This helper class will be used to facilitate the printing of database objects as strings
# class MJSONEncoder(JSONEncoder):
#     def default(self, obj):
#         if isinstance(obj, decimal.Decimal):
#             # Convert decimal instances to strings.
#             return str(obj)
#         return super(MJSONEncoder, self).default(obj)
#
#
# app.json_encoder = MJSONEncoder


class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(120), unique=True)
    password_hash = db.Column(db.String(128))

    def hash_password(self, password):
        self.password_hash = pwd_context.encrypt(password)
        print(self.password_hash)

    def verify_password(self, password):
        return pwd_context.verify(password, self.password_hash)

    def generate_auth_token(self, expiration=600):
        s = Serializer(app.config['SECRET_KEY'], expires_in=expiration)
        return s.dumps({'id': self.id})

    @staticmethod
    def verify_auth_token(token):
        print ('48 - ' + token)
        s = Serializer(app.config['SECRET_KEY'])
        try:
            data = s.loads(token)
        except SignatureExpired:
            return None  # valid token, but expired
        except BadSignature:
            return None  # invalid token
        user = User.query.get(data['id'])
        if user is None:
            return
        return user



@auth.verify_password
def verify_password(email_or_token, password):
    # first try to authenticate by token
    user = User.verify_auth_token(email_or_token)
    if not user:
        # try to authenticate with username/password
        user = User.query.filter_by(email=email_or_token).first()
        print ('86')
        print (user)
        if not user or not user.verify_password(password):
            return False
    g.user = user
    return True


@app.route('/', methods = ['GET', 'POST'])
def index():
    if request.method == 'POST':
        if request.form['submit'] == 'calculate_btn':
            weight1 = request.form['weight1']
            weight2 = request.form['weight2']
            print (weight1)
            print (weight2)
            # my_total = calculate(weight1, weight2)
            # print (my_total)
            my_total = 69

            return my_total
    if request.method == 'GET':
        return render_template('index.html')




@app.route('/calculate_total/', methods = ['GET'])
def calculate():
    print (request)
    print (request.view_args)
    item1 = (request.args.get('item1'))
    item2 = (request.args.get('item2'))
    price1 = (request.args.get('price1'))
    price2 = (request.args.get('price2'))
    weight1 = (request.args.get('weight1'))
    weight2 = (request.args.get('weight2'))

    # total2 = float(total)
    # new_total = 1.0 + total2
    # print(new_total)

    item1_byWeight = float(price1) / float(weight1);
    item2_byWeight = float(price2) / float(weight2);

    if (item1_byWeight < item2_byWeight) :
        difference = float(item2_byWeight) - float(item1_byWeight)
        result = (item1 + "is cheapter by " + difference)
    else :
        difference = float(item1_byWeight) - float(item2_byWeight)
        result = (item2 + "is cheapter by " + difference)
    print(result)

    return result


def calculate(weight1, weight2):
    total = weight1 + weight2
    return total


@app.route('/login', methods=['POST'])
def login():
    if request.headers['content-Type'] == 'application/x-www-form-urlencoded':
        email = request.form['email']
        password = request.form['password']
        if email is None or password is None:
            abort(400)
        if User.query.filter_by(email=email).first() is not None:
            verify = verify_password(email, password)
            user = User(email=email)
            print('108 - ' + verify)
            if verify:
                print('You already in there\n')
                return render_template('success.html')
            else:
                print ('Login failed')
                return 'Login failed'

        user = User(email=email)
        User.hash_password(user, password)
        db.session.add(user)
        db.session.commit()
        return render_template('success.html')
    elif request.headers['Content-Type'] == 'application/json':
        print ('122')
        print(request.json)
        email = request.json.get('email')
        password = request.json.get('password')
        if email is None or password is None:
            abort(400)
        if User.query.filter_by(email=email).first() is not None:
            verify = verify_password(email, password)
            user = User(email=email)
            print ('130')
            print (verify)
            if verify:
                print (g.user.id)
                token = g.user.generate_auth_token(600)
                return jsonify({'email': user.email, 'authToken': token.decode('ascii')}), 201, {
                    'Location': url_for('get_user', id=g.user.id, _external=True)}
            else:
                print ('Error: Login Unsuccessful')
                return 'Error: Login Unsuccessful'

        user = User(email=email)
        User.hash_password(user, password)
        db.session.add(user)
        db.session.commit()
        verify_password(email, password)
        token = g.user.generate_auth_token(600)
        return jsonify({'email': user.email, 'authToken': token.decode('ascii')}), 201, {'Location': url_for('get_user', id=user.id, _external=True)}


@app.route('/users/<int:id>')
@auth.login_required
def get_user(id):
    user = User.query.get(id)
    if not user:
        abort(400)
    return jsonify({'email': user.email, 'password': user.password_hash})


@app.route('/token')
@auth.login_required
def get_auth_token():
    token = g.user.generate_auth_token(600)
    return jsonify({'token': token.decode('ascii'), 'duration': 600})


@app.route('/resource')
@auth.login_required
def get_resource():
    return jsonify({'data': 'Hello, %s!' % g.user.email})


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