# SMTP Plugins for cherrypy
# Copyright (C) 2022-2026 IKUS Software
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

from unittest import mock, skipUnless

import cherrypy
from cherrypy.test import helper
from parameterized import parameterized

from .. import smtp  # noqa


class SmtpPluginTest(helper.CPWebCase):
    @classmethod
    def setup_server(cls):
        cherrypy.config.update(
            {
                'smtp.server': '__default__',
                'smtp.username': 'username',
                'smtp.password': 'password',
                'smtp.email_from': 'Test <email_from@test.com>',
            }
        )

    def test_send_mail(self):
        # Given a valid smtp server
        with mock.patch(smtp.__name__ + '.smtplib') as smtplib:
            # When publishing a send_mail
            cherrypy.engine.publish('send_mail', to='target@test.com', subject='subjet', message='body')
            # Then smtplib is called to send the mail.
            smtplib.SMTP.assert_called_once_with('__default__', 25)
            smtplib.SMTP.return_value.send_message.assert_called_once_with(mock.ANY)
            smtplib.SMTP.return_value.quit.assert_called_once_with()

    def test_send_mail_with_to_tuple(self):
        # Given a valid smtp server
        with mock.patch(smtp.__name__ + '.smtplib') as smtplib:
            # When publishing a send_mail
            cherrypy.engine.publish(
                'send_mail',
                to=('A name', 'target@test.com'),
                subject='subjet',
                message='body',
                bcc=('A bcc name', 'bcc@test.com'),
                reply_to=('A Reply Name', 'replyto@test.com'),
            )
            # Then smtplib is called to send the mail.
            smtplib.SMTP.assert_called_once_with('__default__', 25)
            smtplib.SMTP.return_value.send_message.assert_called_once_with(mock.ANY)
            smtplib.SMTP.return_value.quit.assert_called_once_with()

    @skipUnless(hasattr(cherrypy, 'scheduler'), reason='Required scheduler')
    def test_queue_mail(self):
        with mock.patch(smtp.__name__ + '.smtplib') as smtplib:
            # Given a mail being queued.
            cherrypy.engine.publish('queue_mail', to='target@test.com', subject='subjet', message='body')
            # When waiting for all task to be processed
            cherrypy.scheduler.wait_for_jobs()
            # Then smtplib is called to send the mail.
            smtplib.SMTP.assert_called_once_with('__default__', 25)
            smtplib.SMTP.return_value.send_message.assert_called_once_with(mock.ANY)
            smtplib.SMTP.return_value.quit.assert_called_once_with()

    def test_html2plaintext(self):
        """
        Check if this convertion is working fine.
        """

        html = """<html>
  <head>
    <style type="text/css">
      body { font-family:Helvetica; }
    </style>
  </head>
  <body>
    <h1>Hi!</h1>
    <p id="test"
        class="mb-2 text-center">
      How are you?<br/>
      Here&#160;is the <a href="https://www.python.org">link</a> you wanted.
    </p>
  </body>
</html>
"""

        expected = """**Hi!**
How are you?
Here is the link [1] you wanted.

[1] https://www.python.org"""
        self.assertEqual(expected, smtp._html2plaintext(html))

    def test_formataddr(self):
        self.assertEqual('test@test.com', smtp._formataddr('test@test.com'))
        self.assertEqual('TEST <test@test.com>', smtp._formataddr(('TEST', 'test@test.com')))
        self.assertEqual(
            'test2@test.com, TEST3 <test3@test.com>', smtp._formataddr(['test2@test.com', ('TEST3', 'test3@test.com')])
        )

    @parameterized.expand(
        [
            (None, None, None),
            (None, 'test2@test.com', 'test2@test.com'),
            ('test2@test.com', None, 'test2@test.com'),
            ('test1@test.com', 'test2@test.com', 'test1@test.com, test2@test.com'),
        ]
    )
    def test_with_bcc(self, smtp_bcc, bcc, expected_bcc):
        # Given a valid smtp server
        with mock.patch(smtp.__name__ + '.smtplib') as smtplib:
            # Given bcc is defined at plugin level.
            cherrypy.smtp.bcc = smtp_bcc
            # When publishing a send_mail with Bcc
            cherrypy.engine.publish(
                'send_mail',
                to=('A name', 'target@test.com'),
                subject='subjet',
                message='body',
                bcc=bcc,
            )
            # Then message is sent
            smtplib.SMTP.assert_called_once_with('__default__', 25)
            smtplib.SMTP.return_value.send_message.assert_called_once_with(mock.ANY)
            msg = smtplib.SMTP.return_value.send_message.call_args.args[0]
            smtplib.SMTP.return_value.quit.assert_called_once_with()
            # Message include our expected Bcc
            self.assertEqual(expected_bcc, msg['Bcc'])
