# -*- coding: utf-8 -*-
from .validators import cssClassConstraint
from .validators import isTALES
from collective.easyform import config
from collective.easyform import easyformMessageFactory as _  # NOQA
from plone.app.textfield import RichText
from plone.autoform import directives
from plone.schemaeditor.interfaces import IFieldContext
from plone.schemaeditor.interfaces import IFieldEditorExtender
from plone.schemaeditor.interfaces import ISchemaContext
from plone.schemaeditor.schema import ITextLinesField
from plone.supermodel.directives import fieldset
from plone.supermodel.model import Schema
import z3c.form
from z3c.form.interfaces import IFieldWidget
from zope import schema
from zope.component import getGlobalSiteManager
from zope.interface import Interface
from zope.interface import provider
from zope.schema.interfaces import IContextSourceBinder
from zope.schema.vocabulary import SimpleVocabulary

import six
import z3c.form.interfaces
import zope.interface
import zope.schema.interfaces


class WidgetVocabulary(SimpleVocabulary):
    def getTerm(self, value):
        """See zope.schema.interfaces.IBaseVocabulary"""
        if not isinstance(value, six.string_types):
            value = "{0}.{1}".format(
                value.widget_factory.__module__, value.widget_factory.__name__
            )
        return self.getTermByToken(value)


@provider(IContextSourceBinder)
def widgetsFactory(context):
    terms = []
    adapters = [
        a.factory
        for a in getGlobalSiteManager().registeredAdapters()
        if (
            a.provided == IFieldWidget
            and len(a.required) == 2
            and a.required[0].providedBy(context)
        )
    ]
    for adapter in set(adapters):
        name = u"{0}.{1}".format(adapter.__module__, adapter.__name__)
        terms.append(WidgetVocabulary.createTerm(name, str(name), adapter.__name__))
    return WidgetVocabulary(terms)


class IEasyFormFieldsEditorExtender(IFieldEditorExtender):
    pass


class IFieldExtender(Schema):
    fieldset(
        u"advanced",
        label=_("Advanced"),
        fields=["field_widget", "validators", "THidden", "depends_on", "css_class",],
    )
    directives.write_permission(field_widget=config.EDIT_ADVANCED_PERMISSION)
    field_widget = zope.schema.Choice(
        title=_(u"label_field_widget", default=u"Field Widget"),
        description=_(u"help_field_widget", default=u""),
        required=False,
        source=widgetsFactory,
    )
    directives.write_permission(validators=config.EDIT_ADVANCED_PERMISSION)
    validators = zope.schema.List(
        title=_("Validators"),
        description=_(
            u"help_userfield_validators",
            default=u"Select the validators to use on this field",
        ),
        unique=True,
        required=False,
        value_type=zope.schema.Choice(vocabulary="easyform.Validators"),
    )
    directives.write_permission(THidden=config.EDIT_TALES_PERMISSION)
    THidden = zope.schema.Bool(
        title=_(u"label_hidden", default=u"Hidden"),
        description=_(u"help_hidden", default=u"Field is hidden"),
        required=False,
        default=False,
    )
    directives.write_permission(depends_on=config.EDIT_TALES_PERMISSION)
    depends_on = zope.schema.TextLine(
        title=_(
            u'Field depends on',
        ),
        description=_(
            u'This is using the pat-depends from patternslib, all options are supported. Please read the <a href="https://patternslib.com/demos/depends" target="_blank">pat-depends documentations</a> for options.',
        ),
        default=u'',
        required=False,
    )
    directives.write_permission(css_class=config.EDIT_TALES_PERMISSION)
    css_class = zope.schema.TextLine(
        title=_(
            u'CSS Class',
        ),
        description=_(
            u'Define additional CSS class for this field here. This allowes for formating individual fields via CSS.',
        ),
        default=u'',
        required=False,
        constraint=cssClassConstraint,
    )
    fieldset(
        u"overrides",
        label=_("Overrides"),
        fields=["TDefault", "TEnabled", "TValidator", "serverSide"],
    )
    directives.write_permission(TDefault=config.EDIT_TALES_PERMISSION)
    TDefault = zope.schema.TextLine(
        title=_(u"label_tdefault_text", default=u"Default Expression"),
        description=_(
            u"help_tdefault_text",
            default=u"A TALES expression that will be evaluated when the form"
            u"is displayed to get the field default value. Leave "
            u"empty if unneeded. Your expression should evaluate as a "
            u"string. PLEASE NOTE: errors in the evaluation of this "
            u"expression will cause an error on form display.",
        ),
        default=u"",
        constraint=isTALES,
        required=False,
    )
    directives.write_permission(TEnabled=config.EDIT_TALES_PERMISSION)
    TEnabled = zope.schema.TextLine(
        title=_(u"label_tenabled_text", default=u"Enabling Expression"),
        description=_(
            u"help_tenabled_text",
            default=u"A TALES expression that will be evaluated when the form "
            u"is displayed to determine whether or not the field is "
            u"enabled. Your expression should evaluate as True if "
            u"the field should be included in the form, False if it "
            u"should be omitted. Leave this expression field empty "
            u"if unneeded: the field will be included. PLEASE NOTE: "
            u"errors in the evaluation of this expression will cause "
            u"an error on form display.",
        ),
        default=u"",
        constraint=isTALES,
        required=False,
    )
    directives.write_permission(TValidator=config.EDIT_TALES_PERMISSION)
    TValidator = zope.schema.TextLine(
        title=_(u"label_tvalidator_text", default=u"Custom Validator"),
        description=_(
            u"help_tvalidator_text",
            default=u"A TALES expression that will be evaluated when the form "
            u"is validated. Validate against 'value', which will "
            u"contain the field input. Return False if valid; if not "
            u"valid return a string error message. E.G., "
            u"\"python: test(value=='eggs', False, 'input must be "
            u'eggs\')" will require "eggs" for input. '
            u"PLEASE NOTE: errors in the evaluation of this "
            u"expression will cause an error on form display.",
        ),
        default=u"",
        constraint=isTALES,
        required=False,
    )
    directives.write_permission(serverSide=config.EDIT_TALES_PERMISSION)
    serverSide = zope.schema.Bool(
        title=_(u"label_server_side_text", default=u"Server-Side Variable"),
        description=_(
            u"description_server_side_text",
            default=u""
            u"Mark this field as a value to be injected into the "
            u"request form for use by action adapters and is not "
            u"modifiable by or exposed to the client.",
        ),
        default=False,
        required=False,
    )


class IEasyFormFieldsContext(ISchemaContext):
    """EasyForm schema view interface."""


class IEasyFormFieldContext(IFieldContext):
    """EasyForm field content marker."""


class ILabel(zope.schema.interfaces.IField):
    """Label Field."""


class IRichLabel(ILabel):
    """Rich Label Field."""

    rich_label = RichText(title=_(u"Rich Label"), default=u"", missing_value=u"")


class IEasyFormWidget(z3c.form.interfaces.IWidget):
    """General marker for easyform widgets."""


class ILabelWidget(IEasyFormWidget):
    """Label Widget."""


class IRichLabelWidget(IEasyFormWidget):
    """Rich Label Field Widget."""


class IReCaptcha(zope.schema.interfaces.ITextLine):
    """ReCaptcha Field."""


class IHCaptcha(zope.schema.interfaces.ITextLine):
    """ReCaptcha Field."""


class INorobotCaptcha(zope.schema.interfaces.ITextLine):
    """Norobot Field."""


class ILikert(zope.schema.interfaces.IField):

    questions = zope.schema.List(
        title=_(u'Possible questions'),
        description=_(u'Enter allowed choices one per line.'),
        required=zope.schema.interfaces.IChoice['vocabulary'].required,
        default=zope.schema.interfaces.IChoice['vocabulary'].default,
        value_type=zope.schema.TextLine())
    zope.interface.alsoProvides(questions, ITextLinesField)

    answers = zope.schema.List(
        title=_(u'Possible answers'),
        description=_(u'Enter allowed choices one per line.'),
        required=zope.schema.interfaces.IChoice['vocabulary'].required,
        default=zope.schema.interfaces.IChoice['vocabulary'].default,
        value_type=zope.schema.TextLine())
    zope.interface.alsoProvides(questions, ITextLinesField)

class ILikertWidget(IEasyFormWidget):
    """Likert widget."""


class IFieldValidator(Interface):
    """Base marker for field validators."""
