import datetime
import re

from rest_framework import serializers

from access.serializers.organization import TenantBaseSerializer

from api.models.tokens import AuthToken
from api.serializers import common

from core import exceptions as centurion_exception



class AuthTokenBaseSerializer(serializers.ModelSerializer):

    display_name = serializers.SerializerMethodField('get_display_name')

    def get_display_name(self, item) -> str:

        return str( item )

    url = serializers.HyperlinkedIdentityField(
        view_name="v2:_api_v2_cluster-detail",
    )

    class Meta:

        model = AuthToken

        fields = [
            'id',
            'display_name',
            'url',
        ]

        read_only_fields = [
            'id',
            'display_name',
            'url',
        ]


class AuthTokenModelSerializer(
    common.CommonModelSerializer,
    AuthTokenBaseSerializer
):

    _urls = serializers.SerializerMethodField('get_url')

    def get_url(self, item) -> dict:

        get_url = super().get_url( item = item )

        del get_url['history']
        del get_url['knowledge_base']


        return get_url


    expires = serializers.DateTimeField(
        initial = (datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(days=90)).replace(microsecond=0).isoformat(),
        )

    token = serializers.CharField(initial=AuthToken().generate, write_only = True )


    class Meta:

        model = AuthToken

        fields =  [
            'id',
            'display_name',
            'note',
            'token',
            'user',
            'expires',
            'created',
            'modified',
            '_urls',
        ]

        read_only_fields = [
            'id',
            'display_name',
            'user',
            'created',
            'modified',
            '_urls',
        ]


    def validate(self, attrs):

        if self.context['request'].user.id != int(self.context['view'].kwargs['model_id']):

            raise centurion_exception.PermissionDenied()


        if not self.Meta.model().validate_note_no_token(attrs['note'], attrs['token']):

            raise centurion_exception.ValidationError(
                detail = {
                    "note": "No more than nine chars of token can be contained within the notes field"
                },
                code = 'note_no_contain_token'
            )


        if not re.fullmatch(r'[0-9|a-f]{64}', str(attrs['token']).lower()):


            raise centurion_exception.ValidationError(
                detail = {
                    "token": "Token appears to have been edited."
                },
                code = 'token_not_sha256'
            )


        attrs['token'] = self.Meta.model().token_hash(attrs['token'])

        attrs = super().validate(attrs)

        attrs['user'] = self.context['request'].user

        return attrs



class AuthTokenViewSerializer(AuthTokenModelSerializer):

    organization = TenantBaseSerializer( many = False, read_only = True )
