from lxml import etree
from plone import api
from plone.app.registry.browser.edit import RecordEditForm
from plone.registry.interfaces import IRegistry
from ploneintranet.userprofile.browser.forms import get_fields_for_template
from ploneintranet.userprofile.browser.forms import icon_for_field
from ploneintranet.userprofile.browser.forms import UserProfileEditForm
from ploneintranet.userprofile.browser.forms import UserProfileViewForm
from ploneintranet.userprofile.content.userprofile import IUserProfile
from ploneintranet.userprofile.content.userprofile import IUserProfileAdditional
from ploneintranet.userprofile.tests.base import BaseTestCase
from zope import schema
from zope.component import getUtility
from zope.component.hooks import getSite


class TestUtilities(BaseTestCase):
    def test_icon_for_field(self):
        self.assertEqual(icon_for_field("email"), "icon-mail")
        self.assertEqual(icon_for_field("this-is-not-a-known-field"), "icon-right-open")


class TestUserProfileEditForm(BaseTestCase):
    def setUp(self):
        super().setUp()
        self.login_as_portal_owner()
        self.profile1 = api.content.create(
            container=self.profiles,
            type="ploneintranet.userprofile.userprofile",
            id="johndoe",
            username="johndoe",
            first_name="John",
            last_name="Doe",
        )

    def test_fields(self):
        form = UserProfileEditForm(self.profile1, self.request)
        form.update()
        fields = list(form.fields.keys())

        # By default should include all core fields except:
        # - portrait
        # - recent_contacts
        # - the ones listed in the ploneintranet.userprofile.hidden_fields record
        banned_fields = (
            "portrait",
            "recent_contacts",
        ) + api.portal.get_registry_record("ploneintranet.userprofile.hidden_fields")
        for fieldname in schema.getFieldNames(IUserProfile):
            if fieldname in banned_fields:
                self.assertNotIn(fieldname, fields, f"{fieldname} in edit form")
            else:
                self.assertIn(fieldname, fields, f"{fieldname} missing from edit form")

        # And any additional fields
        for fieldname in schema.getFieldNames(IUserProfileAdditional):
            self.assertIn(
                f"IUserProfileAdditional.{fieldname}",
                fields,
                f"{fieldname} missing from edit form",
            )

    def test_hidden_fields(self):
        api.portal.set_registry_record(
            "ploneintranet.userprofile.hidden_fields", ("first_name", "last_name")
        )

        form = UserProfileEditForm(self.profile1, self.request)
        form.update()
        fields = list(form.fields.keys())

        self.assertNotIn("first_name", fields)
        self.assertNotIn("last_name", fields)

    def test_allow_to_empty_hidden_fields(self):
        """Test if the hidden_fields registry entry can also be cleared again."""

        registry = getUtility(IRegistry)
        record = registry.records.get("ploneintranet.userprofile.hidden_fields")

        request = self.request.clone()
        request.form["form.widgets.value"] = ""  # empty the hidden_fields value
        form = RecordEditForm(getSite(), request)
        form.record = record

        form.update()
        data, errors = form.extractData()
        self.assertEqual(errors, ())

    def test_read_only_fields(self):
        api.portal.set_registry_record(
            "ploneintranet.userprofile.read_only_fields", ("first_name", "last_name")
        )

        form = UserProfileEditForm(self.profile1, self.request)
        form.update()
        fields = list(form.fields.keys())

        self.assertIn("first_name", fields)
        self.assertIn("last_name", fields)

        self.assertEqual(form.widgets["first_name"].mode, "display")
        self.assertEqual(form.widgets["last_name"].mode, "display")

    def test_widgets(self):
        form = UserProfileEditForm(self.profile1, self.request)

        html = form()

        parser = etree.HTMLParser()
        parsed = etree.fromstring(html, parser)

        el_url = parsed.cssselect("#form-widgets-IUserProfileAdditional-url")
        self.assertEqual(len(el_url), 1)
        self.assertEqual(el_url[0].get("type"), "url")

        el_mail = parsed.cssselect("#form-widgets-email")
        self.assertEqual(len(el_mail), 1)
        self.assertEqual(el_mail[0].get("type"), "email")

        el_org = parsed.cssselect("#form-widgets-IUserProfileAdditional-organization")
        self.assertEqual(len(el_org), 1)
        self.assertEqual(el_org[0].get("type"), "text")

        el_ind = parsed.cssselect("#form-widgets-IUserProfileAdditional-industry")
        self.assertEqual(len(el_ind), 1)
        self.assertEqual(el_ind[0].get("type"), "text")


class TestUserProfileViewForm(BaseTestCase):
    def setUp(self):
        super().setUp()
        self.login_as_portal_owner()
        self.profile1 = api.content.create(
            container=self.profiles,
            type="ploneintranet.userprofile.userprofile",
            id="johndoe",
            username="johndoe",
            first_name="John",
            last_name="Doe",
            email="john@doe.com",
        )

    def test_hidden_fields(self):
        api.portal.set_registry_record(
            "ploneintranet.userprofile.hidden_fields", ("first_name", "last_name")
        )

        form = UserProfileViewForm(self.profile1, self.request)
        form.update()
        fields = list(form.fields.keys())

        self.assertNotIn("first_name", fields)
        self.assertNotIn("last_name", fields)
        self.assertNotIn("hide_email", fields)

    def test_get_fields(self):
        form = UserProfileViewForm(self.profile1, self.request)
        form.update()
        fields = list(form.fields.keys())

        fields_for_template = get_fields_for_template(form)
        names = [x["name"] for x in fields_for_template]

        self.assertEqual(names, fields)
        self.assertIn("email", names)

        mapping = {x["name"]: x for x in fields_for_template}
        email = mapping["email"]
        self.assertEqual(email["raw"], "john@doe.com")
        self.assertEqual(email["label"], "Email")

    def test_hide_email(self):
        self.profile1.hide_email = True

        form = UserProfileViewForm(self.profile1, self.request)
        form.update()
        self.assertNotIn("email", form.fields)

    def test_hide_email_default(self):
        # Check that default is False
        self.assertFalse(self.profile1.hide_email)
        api.portal.set_registry_record(
            "ploneintranet.userprofile.hide_email_by_default", True
        )
        # Now the default is True
        self.assertTrue(self.profile1.hide_email)
        self.profile1.hide_email = True
        # Setting the value on the profile, no change
        self.assertTrue(self.profile1.hide_email)
        # Set the default to False again. The value on the profile stays true
        api.portal.set_registry_record(
            "ploneintranet.userprofile.hide_email_by_default", False
        )
        self.assertTrue(self.profile1.hide_email)
