from collections import defaultdict
from ploneintranet import schema as pischema
from ploneintranet.core import _
from ploneintranet.layout.interfaces import IPloneintranetFormLayer
from z3c.form.browser.select import SelectWidget
from z3c.form.interfaces import IFieldWidget
from z3c.form.interfaces import ISelectWidget
from z3c.form.widget import FieldWidget
from zope.component import adapter
from zope.interface import implementer
from zope.interface import implementer_only
from zope.interface import Interface
from zope.schema.interfaces import IChoice


@implementer_only(ISelectWidget)
class PISelectWidget(SelectWidget):
    """Select widget implementation."""

    noValueMessage = _("Unknown")


class ISelectFromOptgroupsWidget(ISelectWidget):
    """Select widget interface with optgroup support."""


@implementer_only(ISelectFromOptgroupsWidget)
class PISelectFromOptgroupsWidget(PISelectWidget):
    """Select widget implementation with optgroup support."""

    @property
    def optgroups(self) -> dict[str | None, list[dict]]:
        """Returns a dict of optgroups, each containing a list of items.

        The attributes optgroup and disabled are usually not found
        in SimpleTerm instances.

        You need to provide your own implementation to add these attributes
        to the terms.

        If you stick with the default z3c.form implementation,
        this property will return a dict with a single optgroup `None`,
        containing all items and the widget will render
        as a normal select field without optgroups.
        """
        optgroups = defaultdict(list)
        for item in self.items:
            try:
                term = self.terms.getTermByToken(item["value"])
            except LookupError:
                continue
            optgroup = getattr(term, "optgroup", None)
            # Also enrich the item with the disabled state of the term,
            # if not already set
            if "disabled" not in item:
                item["disabled"] = getattr(term, "disabled", False)
            optgroups[optgroup].append(item)

        return dict(optgroups)


@adapter(IChoice, Interface, IPloneintranetFormLayer)
@implementer(IFieldWidget)
def PISelectFieldWidget(field, source, request=None):
    """Not much more than a brutal copy/paste of the SelectFieldWidget."""
    if request is None:
        real_request = source
    else:
        real_request = request
    return FieldWidget(field, PISelectWidget(real_request))


@implementer(IFieldWidget)
def PISelectFromOptgroupsFieldWidget(field, source, request=None):
    """Not much more than a brutal copy/paste of the SelectFieldWidget."""
    if request is None:
        real_request = source
    else:
        real_request = request
    return FieldWidget(field, PISelectFromOptgroupsWidget(real_request))


class IPIGooglePlaceSelectWidget(ISelectWidget):
    """Choose a place and display as a link to Google Maps."""


@implementer_only(IPIGooglePlaceSelectWidget)
class PIGooglePlaceSelectWidget(PISelectWidget):
    """Choose a place and display as a link to Google Maps."""


@adapter(pischema.IGooglePlace, Interface, IPloneintranetFormLayer)
@implementer(IFieldWidget)
def PIGooglePlaceSelectFieldWidget(field, source, request=None):
    if request is None:
        real_request = source
    else:
        real_request = request
    return FieldWidget(field, PIGooglePlaceSelectWidget(real_request))
