from unittest import mock
from unittest.mock import MagicMock, Mock

from django.test import Client, TestCase

from tordonate import container
from tordonate.civicrm.forms import SubscriptionForm
from tordonate.civicrm.repository import CivicrmRepositoryMock
from tordonate.utils import make_valid_payload


class SubscriptionFormTests(TestCase):
    newsletter_data = {
        "email_address": "address@email.com",
    }

    @mock.patch("altcha.verify_solution")
    def test_newsletter_signup_validation(self, mock_verify_solution: Mock) -> None:
        mock_verify_solution.return_value = (True, None)
        form = SubscriptionForm(
            data={
                **self.newsletter_data,
                "altcha": make_valid_payload(),
            }
        )
        self.assertTrue(form.is_valid())

    @mock.patch("altcha.verify_solution")
    def test_newsletter_signup_invalid_email(self, mock_verify_solution: Mock) -> None:
        mock_verify_solution.return_value = (True, None)
        form = SubscriptionForm(
            data={
                **self.newsletter_data,
                "email_address": "malformed@email",
                "altcha": make_valid_payload(),
            }
        )
        self.assertFalse(form.is_valid())
        self.assertIsNotNone(form.errors.get("__all__"))

    @mock.patch("altcha.verify_solution")
    def test_newsletter_signup_invalid_altcha(self, mock_verify_solution: Mock) -> None:
        mock_verify_solution.return_value = (False, None)
        form = SubscriptionForm(
            data={
                **self.newsletter_data,
                "altcha": make_valid_payload(),
            }
        )
        self.assertFalse(form.is_valid())

    @mock.patch("altcha.verify_solution")
    def test_newsletter_signup_post_results(self, mock_verify_solution: Mock) -> None:
        mock_verify_solution.return_value = (True, None)
        client = Client()
        civi_mock = MagicMock(spec=CivicrmRepositoryMock)
        civi_mock.newsletter_signup_sync = MagicMock()
        civi_mock.newsletter_signup_sync.side_effect = None
        with container.civi.override(civi_mock):
            response = client.post(
                '/subscribe/',
                follow=True,
                data={
                    **self.newsletter_data,
                    "altcha": make_valid_payload(),
                }
            )
            self.assertEqual(response.status_code, 200)
            self.assertTrue(civi_mock.newsletter_signup_sync.called)

    @mock.patch("altcha.verify_solution")
    def test_newsletter_signup_post_results_failed(self, mock_verify_solution: Mock) -> None:
        mock_verify_solution.return_value = (False, None)
        client = Client()
        civi_mock = MagicMock(spec=CivicrmRepositoryMock)
        civi_mock.newsletter_signup_sync = MagicMock()
        civi_mock.newsletter_signup_sync.side_effect = None
        with container.civi.override(civi_mock):
            response = client.post(
                '/subscribe/',
                follow=True,
                data={
                    **self.newsletter_data,
                    "altcha": make_valid_payload(),
                }
            )
            self.assertEqual(response.status_code, 200)
            self.assertFalse(civi_mock.newsletter_signup_sync.called)
