from plone.app.z3cform.widgets.base import HTMLInputWidget
from plone.namedfile.file import NamedBlobFile
from plone.namedfile.file import NamedBlobImage
from ploneintranet.layout.interfaces import IPloneintranetFormLayer
from ploneintranet.schema.interfaces import IMultipleFileInput
from z3c.form.converter import BaseDataConverter
from z3c.form.interfaces import IFieldWidget
from z3c.form.interfaces import IWidget
from z3c.form.interfaces import NO_VALUE
from z3c.form.widget import FieldWidget
from z3c.form.widget import Widget
from zope.component import adapter
from zope.interface import implementer
from zope.interface import implementer_only
from ZPublisher.HTTPRequest import FileUpload


class IMultipleFileInputWidget(IWidget):
    """Marker interface for a custom multiple file input widget"""


@implementer_only(IMultipleFileInputWidget)
class MultipleFileInputWidget(HTMLInputWidget, Widget):
    """Support multiple file input fields.

    These fields allow users to upload multiple files at once.
    """

    klass = "multi-file-widget"
    style = ""
    lang = ""
    title = ""

    def extract(self, default=NO_VALUE):
        """Extract the list of file uploads from the request.

        If we have just a single file upload,
        we wrap it in a list to maintain consistency.
        """
        value = super().extract(default)
        if isinstance(value, FileUpload):
            if value.filename == "":
                # This happens when the user submits the form without
                # selecting a file.
                return []
            return [value]
        return value

    @property
    def accept(self):
        """Return the accept attribute for the file input, if specified."""
        accept = getattr(self.field, "accept", None)
        if isinstance(accept, (list, tuple)):
            return ",".join(accept)
        return None


@adapter(IMultipleFileInput, IPloneintranetFormLayer)
@implementer(IFieldWidget)
def MultipleFileInputFieldWidget(field, request):
    return FieldWidget(field, MultipleFileInputWidget(request))


@adapter(IMultipleFileInput, MultipleFileInputWidget)
class MultipleFileInputDataConverter(BaseDataConverter):
    """Convert between the list of files and the list of file names.

    This widget is used in ploneintranet.news, see the carousel_slides field.
    It's a complex widget that is not yet exposed in the component library.
    """

    def toFieldValue(self, value) -> list[NamedBlobFile | NamedBlobImage] | None:
        """The widget expects a list of file upload values"""
        if isinstance(value, FileUpload):
            value = [value]
        if not isinstance(value, list):
            raise ValueError("Value must be a list of file uploads")
        constructor = self.field.value_type._type

        return [
            constructor(
                data=file_upload.file.read(),
                filename=file_upload.filename,
                contentType=file_upload.headers.get("Content-Type", ""),
            )
            for file_upload in value
        ]
