import io
import uuid
from django import forms
from django.conf import settings
from django.core.validators import FileExtensionValidator
from django import get_version
from django.http import Http404
from django.utils.module_loading import import_string
from django.core.exceptions import ImproperlyConfigured
from django.http import JsonResponse
from django.core.files.base import ContentFile
from PIL import Image

if get_version() >= "4.0":
    from django.utils.translation import gettext_lazy as _
else:
    from django.utils.translation import ugettext_lazy as _



class UploadFileForm(forms.Form):
    upload = forms.FileField(
        validators=[
            FileExtensionValidator(
                getattr(
                    settings,
                    "CKEDITOR_5_UPLOAD_FILE_TYPES",
                    ["jpeg", "png", "gif", "bmp", "webp", "tiff"],
                ),
            ),
        ],
    )


class NoImageException(Exception):
    pass

def get_storage_class():
    storage_setting = getattr(settings, "CKEDITOR_5_FILE_STORAGE", None)
    default_storage_setting = getattr(settings, "DEFAULT_FILE_STORAGE", None)
    
    storages_setting = getattr(settings, "STORAGES", {})
    default_storage_name = storages_setting.get("default", {}).get("BACKEND")

    if storage_setting:
        return import_string(storage_setting)
    elif default_storage_setting:
        try:
            return import_string(default_storage_setting)
        except ImportError:
            error_msg = f"Invalid default storage class: {default_storage_setting}"
            raise ImproperlyConfigured(error_msg)
    elif default_storage_name:
        try:
            return import_string(default_storage_name)
        except ImportError:
            error_msg = f"Invalid default storage class: {default_storage_name}"
            raise ImproperlyConfigured(error_msg)
    else:
        error_msg = ("Either CKEDITOR_5_FILE_STORAGE, DEFAULT_FILE_STORAGE, "
                     "or STORAGES['default'] setting is required.")
        raise ImproperlyConfigured(error_msg)


storage = get_storage_class()


def image_verify(f):
    try:
        Image.open(f).verify()
    except OSError:
        raise NoImageException


def handle_uploaded_file(f, all=False):
    fs = storage()
    default_storage = getattr(settings, "CKEDITOR_5_FILE_UPLOAD", "")
    if not all:
        image = Image.open(f)
        image_bytes = io.BytesIO()
        image.save(fp=image_bytes, format="WEBP")
        f = ContentFile(content=image_bytes.getvalue())
        d = f"{default_storage}{uuid.uuid4().hex}.webp"
        filename = fs.save(d, f)
        return fs.url(filename)
    d = f"{default_storage}{f.name}"
    filename = fs.save(d, f)
    return fs.url(filename)


def custom_upload_function(request):
    if request.method == "POST" and request.user.is_staff:
        form = UploadFileForm(request.POST, request.FILES)
        allow_all_file_types = getattr(settings, "CKEDITOR_5_ALLOW_ALL_FILE_TYPES", False)

        if not allow_all_file_types:
            try:
                image_verify(request.FILES['upload'])
            except NoImageException as ex:
                return JsonResponse({"error": {"message": f"{ex}"}}, status=400)
        if form.is_valid():
            url = handle_uploaded_file(request.FILES["upload"], allow_all_file_types)
            return JsonResponse({"url": url})
    raise Http404(_("Page not found."))
