import re

from django.core.exceptions import ValidationError
from django.core.files.uploadedfile import UploadedFile
from django.core.validators import BaseValidator
from django.http import HttpResponseBadRequest
from rest_framework import status
from rest_framework.utils import json

from base.constants import FileFieldConstants


def check_path_is_allowed(string):
    pattern = r"api/v1/(vehicle/insurance|master/upload/(amenities|connectors|locations|network)/csv|station/upload/csv|vehicle/insurance)"
    return bool(re.search(pattern, string))


class FileValidator(BaseValidator):
    """
    Validates the file size and extension of an uploaded file.

    Args:
        message (str, optional): The error message to display if the file is invalid.
                                 Defaults to a message indicating the allowed file formats
                                 and the maximum file size.
    """

    message = (
        f"Invalid file type or exceeds maximum file size. "
        f"(Allowed file formats: {', '.join(FileFieldConstants.IMAGE_FORMATS)}, maximum file size: 15 MB)"
    )

    def __call__(self, value: UploadedFile):
        """
        Validates the given `value` (an UploadedFile instance).

        Args:
            value (UploadedFile): The file to validate.

        Raises:
            ValidationError: If the file is invalid.
        """

        if value.size > FileFieldConstants.FILE_SIZE:  # Limit to 15 MB
            raise ValidationError(self.message)

        ext = value.name.split(".")[-1].lower()
        if ext not in FileFieldConstants.IMAGE_FORMATS:
            raise ValidationError(self.message)


class FileValidationMiddleware:
    """
    Middleware that validates uploaded files.

    Args:
        get_response (callable): The callable to be called after processing the request.
    """

    def __init__(self, get_response):
        """
        Initializes the middleware with the given `get_response` callable.

        Args:
            get_response (callable): The callable to be called after processing the request.
        """
        self.get_response = get_response

    def __call__(self, request):
        """
        Processes the incoming request, validating uploaded files if necessary.

        Args:
            request (HttpRequest): The HTTP request to process.

        Returns:
            HttpResponse: The response to return to the client.
        """
        if not check_path_is_allowed(request.path):
            if request.method in ("POST", "PUT", "PATCH"):
                for field_name, value in request.FILES.items():
                    if isinstance(value, UploadedFile):
                        try:
                            FileValidator(FileFieldConstants.FILE_SIZE)(value)
                        except ValidationError as e:
                            response = {
                                "code": status.HTTP_400_BAD_REQUEST,
                                "status": "BAD_REQUEST",
                                "message": e.messages[0],
                            }
                            return HttpResponseBadRequest(
                                json.dumps(response), content_type="application/json"
                            )

        return self.get_response(request)
