import os
import re

import rethinkdb as r
from jose import jwt
from jose.exceptions import JWTError
from datetime import datetime
from passlib.hash import pbkdf2_sha256

from flask import current_app

from api.utils.errors import ValidationError, DatabaseProcessError, UnavailableContentError

from api.models.RethinkDBModel import RethinkDBModel

conn = r.connect(db='papers')

class User(RethinkDBModel):
    _table = 'users'

    @classmethod
    def create(cls, **kwargs):
        fullname = kwargs.get('fullname')
        email = kwargs.get('email')
        password = kwargs.get('password')
        password_conf = kwargs.get('password_conf')

        street_number = kwargs.get('street_number')
        route = kwargs.get('route')
        locality = kwargs.get('locality')
        postal_town = kwargs.get('postal_town')
        administrative_area_level_2 = kwargs.get('administrative_area_level_2')
        administrative_area_level_1 = kwargs.get('administrative_area_level_1')
        country = kwargs.get('country')
        postal_code = kwargs.get('postal_code')
        ocp_admin = kwargs.get('ocp_admin')

        if password != password_conf:
            raise ValidationError("Password and Confirm password need to be the same value")
        password = cls.hash_password(password)
        doc = {
            'fullname': fullname,
            'email': email,
            'password': password,
            'ocp_admin': ocp_admin,
            'address': {
                'street_number': street_number,
                'route': route,
                'locality': locality,
                'postal_town': postal_town,
                'administrative_area_level_2': administrative_area_level_2,
                'administrative_area_level_1': administrative_area_level_1,
                'country': country,
                'postal_code': postal_code
            },
            'date_created': datetime.now(r.make_timezone('+01:00')),
            'date_modified': datetime.now(r.make_timezone('+01:00')),
        }

        print(doc)

        users = list(r.table(cls._table).filter({'email': email}).run(conn))
        if len(users):
            raise ValidationError("Could already exists with e-mail address: {0}".format(email))

        r.table(cls._table).insert(doc).run(conn)

    @classmethod
    def validate(cls, email, password):
        docs = list(r.table(cls._table).filter({'email': email}).run(conn))

        if not len(docs):
            raise ValidationError("Could not find the e-mail address you specified")

        _hash = docs[0]['password']

        if cls.verify_password(password, _hash):
            try:
                token = jwt.encode({'id': docs[0]['id']}, current_app.config['SECRET_KEY'], algorithm='HS256')
                return token
            except JWTError:
                raise ValidationError("There was a problem while trying to create a JWT token.")
        else:
            raise ValidationError("The password you inputed was incorrect.")

    @classmethod
    def get_all(cls):
        return list(r.table(cls._table).run(conn))

    @staticmethod
    def hash_password(password):
        return pbkdf2_sha256.encrypt(password, rounds=200000, salt_size=16)

    @staticmethod
    def verify_password(password, _hash):
        return pbkdf2_sha256.verify(password, _hash)
