import binascii
import os
import time
from typing import Optional

from peewee import TextField, BigIntegerField, BlobField
from slim.base.view import AbstractSQLView
from slim.utils import to_bin, get_bytes_from_blob

from model import StdBaseModel, INETField


class UserToken(StdBaseModel):
    user_id = BlobField(index=True)
    expire = BigIntegerField(null=True)

    first_meet_time = BigIntegerField(null=True)
    ip_first_meet = INETField(default=None, null=True)  # 注册IP
    ua_first_meet = TextField(null=True)

    last_access_time = BigIntegerField(null=True)
    ip_latest = INETField(default=None, null=True)
    ua_latest = TextField(null=True)

    class Meta:
        db_table = 'user_token'

    @classmethod
    def new(cls, user_id):
        create_time = int(time.time())
        expire_time = create_time + 30 * 24 * 60 * 60
        token = os.urandom(16)
        return UserToken.create(id=token, time=create_time, user_id=user_id, expire=expire_time)

    @classmethod
    def get_by_token(cls, token) -> Optional['UserToken']:
        if isinstance(token, str):
            try:
                token = to_bin(token)
            except binascii.Error:
                return

        t = cls.get_by_pk(token)
        if t and time.time() < t.expire:
            return t

    def get_token(self):
        return get_bytes_from_blob(self.id)

    async def init(self, view: AbstractSQLView):
        """
        从请求初始化信息
        :param view:
        :return:
        """
        # req = sqlview._request
        self.first_meet_time = int(time.time())
        self.ip_first_meet = await view.get_ip()
        self.ua_first_meet = view.headers.get('User-Agent', None)
        self.save()

    async def access_save(self, view: AbstractSQLView):
        self.last_access_time = int(time.time())
        self.ip_latest = await view.get_ip()
        self.ua_latest = view.headers.get('User-Agent', None)
        self.save()
