from datetime import datetime

from django.db import models
from account.models import SiteUser, SiteAccountManager

from hashlib import sha512
from django.contrib.auth.hashers import check_password

from .api_errors import *


class UserToken(models.Model):
    user = models.ForeignKey(SiteUser, on_delete=models.CASCADE)
    access_token = models.CharField(max_length=128, editable=False, unique=True)
    creation_time = models.DateTimeField(default=datetime.now)

    @staticmethod
    def create_token(user: SiteUser):
        token = UserToken(user=user)
        token.save()

        print(f"created token {token.access_token[:16]}...")

        return token

    @staticmethod
    def auth(login: str, password: str):
        try:
            user = SiteUser.get_by_natural_key(login)
        except Exception:
            raise Exception(API_ERROR_INVALID_LOGIN)

        if not check_password(password, user.password):
            raise Exception(API_ERROR_INVALID_PASSWORD)

        return user

    @staticmethod
    def deauth(token: str):
        t = UserToken.objects.filter(access_token=token)

        if len(t) == 0:
            raise Exception(API_ERROR_INVALID_TOKEN)

        t[0].delete()

    @staticmethod
    def get_user_by_token(token: str):
        return UserToken.get_by_token(token).user

    @staticmethod
    def get_by_token(token: str):
        t = UserToken.objects.filter(access_token=token).select_related('user')

        if len(t) == 0:
            raise Exception(API_ERROR_INVALID_TOKEN)
        return t[0]

    def __str__(self):
        return self.user.email + ": " + self.access_token[:10] + "..."

    def save(self, *args, **kwargs):
        if len(self.access_token) == 0:
            source = bytearray(self.user.email + self.user.password + str(datetime.now()), 'utf-8')
            t = sha512(source).hexdigest()

            # чекаем токен в базе
            if UserToken.objects.filter(access_token=t).count() != 0:
                # по какой-то причине есть, выкидываем исключение
                raise Exception(API_ERROR_TOKEN_CREATION)

            self.access_token = t

        super().save(*args, **kwargs)
