# Path: src/bananas/drf/utils.py
# class HeaderError(ValueError):
#     code = "invalid_header"
# 
#     def as_api_error(self) -> BadRequest:
#         return BadRequest(detail=str(self), code=self.code)
# 
# def parse_header_datetime(request: Request, header: str) -> datetime.datetime:
#     try:
#         value = request.headers[header]
#     except KeyError:
#         raise MissingHeader(header)
#     try:
#         return datetime.datetime.fromtimestamp(
#             parse_http_date(value), tz=datetime.timezone.utc
#         )
#     except ValueError as e:
#         raise InvalidHeader(header) from e
# 
# def parse_header_etags(request: Request, header: str) -> FrozenSet[str]:
#     try:
#         parts = request.headers[header].split(",")
#     except KeyError:
#         raise MissingHeader(header)
#     tags = frozenset(clean_tags(parts))
#     if not tags:
#         raise InvalidHeader(header)
#     return tags


import abc
import datetime
import operator
from functools import wraps
from typing import (
    Any,
    Callable,
    FrozenSet,
    Generic,
    List,
    NoReturn,
    Optional,
    TypeVar,
    cast,
)
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db.models import Model, QuerySet
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework.mixins import UpdateModelMixin
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import BaseSerializer, ModelSerializer
from rest_framework.viewsets import GenericViewSet
from typing_extensions import Final, Protocol, final
from bananas.admin.api.schemas.yasg import BananasSwaggerSchema
from bananas.models import TimeStampedModel
from . import errors
from .utils import HeaderError, parse_header_datetime, parse_header_etags
    )


def allow_if_unmodified_since() -> Fence[TimeStampedModel, datetime.datetime]:
    if not settings.USE_TZ:
        raise ImproperlyConfigured(
            "{} does not support settings.USE_TZ=False.".format(
                allow_if_unmodified_since.__name__
            )
        )
    return Fence(
        get_token=header_date_parser("If-Unmodified-Since"),
        compare=operator.le,
        get_version=parse_date_modified,
        openapi_parameter=openapi.Parameter(
            in_=openapi.IN_HEADER,
            name="If-Unmodified-Since",
            type=openapi.TYPE_STRING,
            required=True,
            description=(
                "Time of last edit of the client's representation of the resource in "
                "RFC7231 format."
            ),
        ),
    )


def header_etag_parser(header: str) -> Callable[[Request], FrozenSet[str]]:
    def parse(request: Request) -> FrozenSet[str]:
        try:

# Path: src/bananas/drf/utils.py
# class HeaderError(ValueError):
#     code = "invalid_header"
# 
#     def as_api_error(self) -> BadRequest:
#         return BadRequest(detail=str(self), code=self.code)
# 
# def parse_header_datetime(request: Request, header: str) -> datetime.datetime:
#     try:
#         value = request.headers[header]
#     except KeyError:
#         raise MissingHeader(header)
#     try:
#         return datetime.datetime.fromtimestamp(
#             parse_http_date(value), tz=datetime.timezone.utc
#         )
#     except ValueError as e:
#         raise InvalidHeader(header) from e
# 
# def parse_header_etags(request: Request, header: str) -> FrozenSet[str]:
#     try:
#         parts = request.headers[header].split(",")
#     except KeyError:
#         raise MissingHeader(header)
#     tags = frozenset(clean_tags(parts))
#     if not tags:
#         raise InvalidHeader(header)
#     return tags


# Path: src/bananas/drf/fencing.py
import abc
import datetime
import operator
from functools import wraps
from typing import (
    Any,
    Callable,
    FrozenSet,
    Generic,
    List,
    NoReturn,
    Optional,
    TypeVar,
    cast,
)
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db.models import Model, QuerySet
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework.mixins import UpdateModelMixin
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import BaseSerializer, ModelSerializer
from rest_framework.viewsets import GenericViewSet
from typing_extensions import Final, Protocol, final
from bananas.admin.api.schemas.yasg import BananasSwaggerSchema
from bananas.models import TimeStampedModel
from . import errors
from .utils import HeaderError, parse_header_datetime, parse_header_etags

    )


def allow_if_unmodified_since() -> Fence[TimeStampedModel, datetime.datetime]:
    if not settings.USE_TZ:
        raise ImproperlyConfigured(
            "{} does not support settings.USE_TZ=False.".format(
                allow_if_unmodified_since.__name__
            )
        )
    return Fence(
        get_token=header_date_parser("If-Unmodified-Since"),
        compare=operator.le,
        get_version=parse_date_modified,
        openapi_parameter=openapi.Parameter(
            in_=openapi.IN_HEADER,
            name="If-Unmodified-Since",
            type=openapi.TYPE_STRING,
            required=True,
            description=(
                "Time of last edit of the client's representation of the resource in "
                "RFC7231 format."
            ),
        ),
    )


def header_etag_parser(header: str) -> Callable[[Request], FrozenSet[str]]:
    def parse(request: Request) -> FrozenSet[str]:
        try:

            return parse_header_etags(request, header)