# Copyright 2016 Jairo Llopis <jairo.llopis@tecnativa.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from unittest import mock

from werkzeug import urls

from odoo.tests.common import HttpCase


class UICase(HttpCase):
    def extract_url(self, mail, *args, **kwargs):
        url = mail.mailing_id._get_unsubscribe_url(self.email, mail.res_id)
        self.assertTrue(urls.url_parse(url).decode_query().get("token"))
        self.assertTrue(url.startswith(self.domain))
        self.url = url.replace(self.domain, "", 1)
        return True

    def setUp(self):
        super().setUp()
        self.email = "test.contact@example.com"
        self.mail_postprocess_patch = mock.patch(
            "odoo.addons.mass_mailing.models.mail_mail.MailMail."
            "_postprocess_sent_message",
            autospec=True,
            side_effect=self.extract_url,
        )

        self.domain = self.env["ir.config_parameter"].get_param("web.base.url")
        List = self.lists = self.env["mailing.list"]
        for n in range(4):
            self.lists += List.create({"name": "test list %d" % n})
        self.contact = self.env["mailing.contact"].create(
            {
                "name": "test contact",
                "email": self.email,
                "list_ids": [(6, False, self.lists.ids)],
            }
        )
        self.mailing = self.env["mailing.mailing"].create(
            {
                "name": "test mailing %d" % n,
                "mailing_model_id": self.env.ref("mass_mailing.model_mailing_list").id,
                "contact_list_ids": [(6, 0, [self.lists[0].id, self.lists[3].id])],
                "reply_to_mode": "update",
                "subject": "Test",
            }
        )
        # HACK https://github.com/odoo/odoo/pull/14429
        self.mailing.body_html = """
            <div>
                <a href="/unsubscribe_from_list">
                    This link should get the unsubscription URL
                </a>
            </div>
        """

    def tearDown(self):
        del self.email, self.lists, self.contact, self.mailing, self.url
        super().tearDown()

    def test_contact_unsubscription(self):
        """Test a mass mailing contact that wants to unsubscribe."""
        # This list we are unsubscribing from, should appear always in UI
        self.lists[0].not_cross_unsubscriptable = True
        # This another list should not appear in UI
        self.lists[2].not_cross_unsubscriptable = True
        # This another list should not appear in UI, even if it is one of
        # the lists of the mailing
        self.lists[3].is_public = False
        # Extract the unsubscription link from the message body
        with self.mail_postprocess_patch:
            self.mailing.action_send_mail()

        self.start_tour(
            self.url, "mass_mailing_custom_unsubscribe_tour_contact", login="admin"
        )

        # Check results from running tour
        self.assertFalse(self.lists[0].subscription_ids.opt_out)
        self.assertTrue(self.lists[1].subscription_ids.opt_out)
        self.assertFalse(self.lists[2].subscription_ids.opt_out)

        cnt = self.contact
        common_domain = [
            ("mass_mailing_id", "=", self.mailing.id),
            ("email", "=", self.email),
            ("unsubscriber_id", "=", "%s,%d" % (cnt._name, cnt.id)),
        ]
        # first unsubscription
        reason = "mass_mailing_custom_unsubscribe.reason_other"
        unsubscription_1 = self.env["mail.unsubscription"].search(
            common_domain
            + [
                ("action", "=", "unsubscription"),
                ("details", "=", "I want to unsubscribe because I want. " "Period."),
                ("reason_id", "=", self.env.ref(reason).id),
            ]
        )
        # second unsubscription
        reason = "mass_mailing_custom_unsubscribe.reason_not_interested"
        unsubscription_2 = self.env["mail.unsubscription"].search(
            common_domain
            + [
                ("action", "=", "unsubscription"),
                ("reason_id", "=", self.env.ref(reason).id),
            ]
        )
        # re-subscription from self.lists[3]
        unsubscription_3 = self.env["mail.unsubscription"].search(
            common_domain + [("action", "=", "subscription")]
        )
        # unsubscriptions above are all unsubscriptions saved during the
        # tour and they are all the existing unsubscriptions
        self.assertEqual(
            unsubscription_1 | unsubscription_2 | unsubscription_3,
            self.env["mail.unsubscription"].search([]),
        )
        self.assertEqual(3, len(self.env["mail.unsubscription"].search([])))

    def test_partner_unsubscription(self):
        """Test a partner that wants to unsubscribe."""
        # Change mailing to be sent to partner
        partner_id = self.env["res.partner"].name_create(
            "Demo Partner <%s>" % self.email
        )[0]
        self.mailing.mailing_model_id = self.env.ref("base.model_res_partner")
        self.mailing.mailing_domain = repr(
            [("is_blacklisted", "=", False), ("id", "=", partner_id)]
        )
        # Extract the unsubscription link from the message body
        with self.mail_postprocess_patch:
            self.mailing.action_send_mail()

        self.start_tour(
            self.url, "mass_mailing_custom_unsubscribe_tour_partner", login="demo"
        )

        # Check results from running tour
        partner = self.env["res.partner"].browse(partner_id)
        self.assertTrue(partner.is_blacklisted)
        reason_xid = "mass_mailing_custom_unsubscribe.reason_not_interested"
        unsubscriptions = self.env["mail.unsubscription"].search(
            [
                ("action", "=", "blacklist_add"),
                ("mass_mailing_id", "=", self.mailing.id),
                ("email", "=", self.email),
                ("unsubscriber_id", "=", "res.partner,%d" % partner_id),
                ("details", "=", False),
                ("reason_id", "=", self.env.ref(reason_xid).id),
            ]
        )
        self.assertEqual(1, len(unsubscriptions))
