from datetime import datetime

from drf_spectacular.utils import extend_schema, extend_schema_view, OpenApiResponse

from api.viewsets.common.public import PublicReadOnlyViewSet

from devops.models.check_ins import CheckIn
from devops.serializers.public_feature_flag import (
    FeatureFlag,
    ViewSerializer,
)
from devops.models.software_enable_feature_flag import SoftwareEnableFeatureFlag

from core import exceptions as centurion_exceptions



@extend_schema_view(
    create = extend_schema(exclude = True),
    destroy = extend_schema(exclude = True),
    list = extend_schema(
        summary = '(public) Fetch all Feature Flags',
        description='',
        responses = {
            200: OpenApiResponse(description='', response=ViewSerializer),
        }
    ),
    retrieve = extend_schema(
        summary = '(public) Fetch a single Feature Flag',
        description='',
        responses = {
            200: OpenApiResponse(description='', response=ViewSerializer),
        }
    ),
    update = extend_schema(exclude = True),
    partial_update = extend_schema(exclude = True)
)
class ViewSet(PublicReadOnlyViewSet):

    filterset_fields = [
        'enabled',
    ]

    search_fields = [
        'description',
        'name',
    ]

    model = FeatureFlag

    view_description: str = 'This endpoint provides the below ' \
        'JSON document for software feature flagging'

    view_name: str = 'Available Feature Flags'


    def get_queryset(self):

        if self.queryset is None:

            enabled_qs = SoftwareEnableFeatureFlag.objects.filter(
                enabled = True,
                software_id = int(self.kwargs['software_id']),
                organization_id = int(self.kwargs['organization_id']),
            )

            if len(enabled_qs) == 0:

                raise centurion_exceptions.NotFound(
                    code = 'organization_not_found'
                )

            queryset = super().get_queryset().filter(
                organization_id = int(self.kwargs['organization_id']),
                software_id = int(self.kwargs['software_id']),
            )

            if(
                len(queryset) == 0
                and len(enabled_qs) == 0
            ):

                raise centurion_exceptions.NotFound(
                    code = 'software_not_found'
                )

            last_modified = None

            for flag in queryset:

                if last_modified is None:

                    last_modified = flag.modified


                if last_modified.timestamp() < flag.modified.timestamp():

                    last_modified = flag.modified


            if self.request.headers.get('if-modified-since', None):

                if type(self.request.headers['if-modified-since']) is datetime:

                    check_date = self.request.headers['if-modified-since']

                else:

                    check_date = datetime.strptime(
                        self.request.headers['if-modified-since'], '%a, %d %b %Y %H:%M:%S %z'
                    )


                if last_modified.replace(
                        microsecond=0
                    ).timestamp() <= check_date.replace(microsecond=0).timestamp():

                    raise centurion_exceptions.NotModified()


            self.last_modified = last_modified

            self.queryset = queryset


            if self.queryset is None:

                raise centurion_exceptions.NotFound(
                        code = 'failsafe_not_found'
                    )

        return self.queryset


    def get_serializer_class(self):

        return ViewSerializer


    def list(self, request, *args, **kwargs):

        response = super().list(request = request, *args, **kwargs)

        if(
            response.status_code == 200
            and self.last_modified
        ):

            response.headers['Last-Modified'] = self.last_modified.strftime(
                '%a, %d %b %Y %H:%M:%S %z'
            )

        if(
            response.status_code == 200
            or response.status_code == 304
        ):    # Only save check-in if no other error occured.

            user_agent = request.headers.get('user-agent', None)

            if user_agent is not None:

                user_agent = str(user_agent).split(' ')
                user_agent = user_agent[( len(user_agent) -1 )]


            CheckIn.objects.create(
                organization_id = self.kwargs['organization_id'],
                software_id = self.kwargs['software_id'],
                deployment_id = request.headers.get('client-id', 'not-provided'),
                version = user_agent,
                feature = 'feature_flag',
            )


        return response
