# """
# we use middlewares in this project and this file store classes of our middlewares
# """
# from datetime import timedelta
#
# from django.utils import timezone
# from rest_framework import status
#
# from exam.models import ExamPage, EXAM_PAGE_STATE_FINISHED, EXAM_PAGE_STATE_SCORES_PUBLISHED, ENTRANCE_TYPE_API_INVITE, Exam, \
#     ENTRANCE_TYPE_PUBLIC
# from exam.serializers import GetExamPageMinimumDataForStudentsSerializer
# from exam.utils import price_calculator_helper
# from payment.models import UserBalanceHistory
# from utils.myresponse import MyResponse
#
#
# class PublicIdValidationAndAuthorizationMiddleware:
#
#     def __init__(self, get_response, device_token_is_optional=True):
#         self.get_response = get_response
#         self.device_token_is_optional = device_token_is_optional
#         # One-time configuration and initialization.
#
#     def __call__(self, request):
#         # Code to be executed for each request before
#         # the view (and later middleware) are called.
#         response = self.get_response(request)
#         # Code to be executed for each request/response after
#         # the view is called.
#         return response
#
#     def process_view(self, request, view_func, view_args, view_kwargs):
#         # ----------------------------- Block 1 -----------------------------
#         # get token and api_key from request and return error if both of them come in request
#         if request.method == 'POST':
#             public_id = request.POST.get('public_id')
#             device_token = request.POST.get('device_token')
#         else:
#             public_id = request.GET.get('public_id')
#             device_token = request.GET.get('device_token')
#
#         if public_id is None:
#             return MyResponse(request, {'status': 'error', 'message': 'Access denied'}, status=status.HTTP_401_UNAUTHORIZED)
#
#         try:
#             exam = Exam.objects.get(public_id=public_id)
#         except:
#             return MyResponse(request, {'status': 'error', 'message': 'Access denied'}, status=status.HTTP_401_UNAUTHORIZED)
#
#         if not self.device_token_is_optional:
#             if device_token is None or device_token == '':
#                 return MyResponse(request, {'status': 'error', 'message': 'Access denied'}, status=status.HTTP_401_UNAUTHORIZED)
#         if exam.deleted:
#             return MyResponse(request, {'status': 'error', 'message': 'The exam has been deleted'}, status=status.HTTP_404_NOT_FOUND)
#
#         try:
#             exam_page = ExamPage.objects.get(device_token=device_token, entrance_type=ENTRANCE_TYPE_PUBLIC)
#             request.middleware_device_token = device_token
#             request.middleware_exam_page = exam_page
#         except:
#             if not self.device_token_is_optional:
#                 return MyResponse(request, {'status': 'error', 'message': 'Access denied'}, status=status.HTTP_401_UNAUTHORIZED)
#
#             request.middleware_device_token = None
#             request.middleware_exam_page = None
#
#         request.middleware_exam = exam
#
#
# class ExamPurchaseHandlerMiddleware:
#
#     def __init__(self, get_response):
#         self.get_response = get_response
#         # One-time configuration and initialization.
#
#     def __call__(self, request):
#         # Code to be executed for each request before
#         # the view (and later middleware) are called.
#         response = self.get_response(request)
#         # Code to be executed for each request/response after
#         # the view is called.
#         return response
#
#     def process_view(self, request, view_func, view_args, view_kwargs):
#         if request.middleware_user is None:
#             return MyResponse(request, {'status': 'error', 'message': 'Access denied'}, status=status.HTTP_401_UNAUTHORIZED)
#
#         if request.middleware_exam_page is None:
#             total_cost, institute_share, wikiazma_share, wage, tax = price_calculator_helper(request.middleware_user,
#                                                                                              request.middleware_exam)
#             user_balance = UserBalanceHistory.get_last_user_balance(request.middleware_user).remaining_balance
#             if user_balance < total_cost:
#                 return MyResponse(request, {'status': 'error', 'message': 'balance is not enough',
#                                             'data': {'total_cost': total_cost, 'balance': user_balance}},
#                                   status=status.HTTP_402_PAYMENT_REQUIRED)
#
#
# class EntranceTokenValidationAndAuthorizationMiddleware:
#
#     def __init__(self, get_response, device_token_is_required=True):
#         self.get_response = get_response
#         self.device_token_is_required = device_token_is_required
#         # One-time configuration and initialization.
#
#     def __call__(self, request):
#         # Code to be executed for each request before
#         # the view (and later middleware) are called.
#         response = self.get_response(request)
#         # Code to be executed for each request/response after
#         # the view is called.
#         return response
#
#     def process_view(self, request, view_func, view_args, view_kwargs):
#         # ----------------------------- Block 1 -----------------------------
#         # get token and api_key from request and return error if both of them come in request
#         if request.method == 'POST':
#             entrance_token = request.POST.get('entrance_token')
#             device_token = request.POST.get('device_token')
#         else:
#             entrance_token = request.GET.get('entrance_token')
#             device_token = request.GET.get('device_token')
#
#         try:
#             if self.device_token_is_required:
#                 if device_token is None or device_token == '':
#                     return MyResponse(request, {'status': 'error', 'message': 'device_token is required'},
#                                       status=status.HTTP_401_UNAUTHORIZED)
#                 exam_page = ExamPage.objects.get(entrance_token=entrance_token,
#                                                  device_token=device_token, entrance_type=ENTRANCE_TYPE_API_INVITE)
#                 # TODO if device_token in the list of device_token_histories, then return a more descriptive error
#                 request.middleware_device_token = device_token
#             else:
#                 exam_page = ExamPage.objects.get(entrance_token=entrance_token, entrance_type=ENTRANCE_TYPE_API_INVITE)
#             request.middleware_exam_page = exam_page
#             request.middleware_exam = exam_page.exam
#             request.middleware_institute_student = exam_page.institute_student
#         except:
#             return MyResponse(request, {'status': 'error', 'message': 'Access denied'}, status=status.HTTP_401_UNAUTHORIZED)
#
#
# class ExamPageStatusValidationMiddleware:
#
#     def __init__(self, get_response, error_if_exam_page_is_none=True):
#         self.get_response = get_response
#         self.error_if_exam_page_is_none = error_if_exam_page_is_none
#         # One-time configuration and initialization.
#
#     def __call__(self, request):
#         # Code to be executed for each request before
#         # the view (and later middleware) are called.
#         response = self.get_response(request)
#         # Code to be executed for each request/response after
#         # the view is called.
#         return response
#
#     def process_view(self, request, view_func, view_args, view_kwargs):
#
#         if request.middleware_exam.paused:
#             return MyResponse(request, {'status': 'exam_paused', 'message': 'The exam has paused'},
#                               status=status.HTTP_400_BAD_REQUEST)
#
#         exam_page = request.middleware_exam_page
#
#         if exam_page is None:
#             if self.error_if_exam_page_is_none:
#                 # critical error
#                 return MyResponse(request, {'status': 'error', 'message': 'Invalid State'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
#             else:
#                 return
#
#         if exam_page.state == EXAM_PAGE_STATE_FINISHED:
#             exam_page_data = GetExamPageMinimumDataForStudentsSerializer(exam_page).data
#             return MyResponse(request, {'status': 'exam_closed', 'message': 'Exam has been closed.', 'data': {'exam_page': exam_page_data}},
#                               status=status.HTTP_400_BAD_REQUEST)
#
#         if exam_page.state == EXAM_PAGE_STATE_SCORES_PUBLISHED:
#             exam_page_data = GetExamPageMinimumDataForStudentsSerializer(exam_page).data
#             return MyResponse(request,
#                               {'status': 'scores_published', 'message': 'Exam has been closed.',
#                                'data': {'exam_page': exam_page_data}},
#                               status=status.HTTP_400_BAD_REQUEST)
#
#         # datetime.now() is not timezone aware
#         # timezone.now() is timezone aware
#         # exam_page.start_date is timezone aware
#         # we can't compare offset-naive and offset-aware datetimes
#         if exam_page.start_date and exam_page.start_date > timezone.now():
#             exam_page_data = GetExamPageMinimumDataForStudentsSerializer(exam_page).data
#             return MyResponse(request,
#                               {'status': 'exam_not_started', 'message': 'Exam is not started.',
#                                'data': {'exam_page': exam_page_data}},
#                               status=status.HTTP_400_BAD_REQUEST)
#
#         if not exam_page.delayable or exam_page.max_delay is None:
#             exam_page.max_delay = timedelta(seconds=0)
#         if exam_page.end_date:
#             if exam_page.duration and exam_page.entrance_date:
#                 if exam_page.end_date < exam_page.entrance_date + exam_page.duration:
#                     # 3616372662
#                     final_end_date = exam_page.end_date + exam_page.max_delay
#                 else:
#                     # 1736756273
#                     final_end_date = exam_page.entrance_date + exam_page.duration + exam_page.max_delay
#             else:
#                 final_end_date = exam_page.end_date + exam_page.max_delay
#                 # 6735673855
#         else:
#             if exam_page.duration and exam_page.entrance_date:
#                 # 417536827
#                 final_end_date = exam_page.entrance_date + exam_page.duration + exam_page.max_delay
#             else:
#                 final_end_date = None
#
#         if final_end_date and final_end_date < timezone.now():
#             exam_page_data = GetExamPageMinimumDataForStudentsSerializer(exam_page).data
#             return MyResponse(request, {'status': 'exam_ended', 'message': 'Exam has ended.', 'data': {'exam_page': exam_page_data}},
#                               status=status.HTTP_400_BAD_REQUEST)
