from unittest.mock import patch
from django.test import TransactionTestCase, override_settings
from . import tests as baseline
from . import providers as p, services as s


class ProviderDispatchTests(TransactionTestCase):
    setUp = baseline.CommunicationTests.setUp
    make_template = baseline.CommunicationTests.make_template
    request = baseline.CommunicationTests.request
    send = baseline.CommunicationTests.send

    @override_settings(COMMUNICATIONS_PRODUCTION=True, COMMUNICATIONS_ALLOW_EXTERNAL=True,
                       COMMUNICATION_PROVIDERS={})
    def test_missing_sms_records_sanitized_configuration_failure(self):
        row = self.send(self.request())
        self.assertEqual(row.status, "FAILED")
        self.assertEqual(row.attempts.get().error_code, "PROVIDER_CONFIGURATION")

    def test_malformed_vendor_result_is_unknown_and_not_retried(self):
        for result in (None, {"status": "SECRET"}, p.DeliveryResult("UNEXPECTED", "SECRET")):
            row = self.request(event_key="MANUAL:"+str(id(result)))
            adapter = p.FakeSmsProvider()
            with patch.object(s, "get_provider", return_value=adapter), patch.object(adapter, "send", return_value=result) as send:
                self.assertEqual(self.send(row).status, "UNKNOWN")
                self.assertEqual(self.send(row).status, "UNKNOWN")
                send.assert_called_once()
            self.assertEqual(row.attempts.get().provider_reference, "")

    def test_email_unknown_preserves_attempt_and_prevents_retry(self):
        template = self.make_template(code="mail", channel="EMAIL", subject="Test")
        row = self.request(template=template)
        with patch.object(s, "get_provider", return_value=p.DjangoEmailProvider()), patch.object(p, "EmailMessage") as message:
            message.return_value.send.side_effect = TimeoutError("SECRET")
            self.assertEqual(self.send(row).status, "UNKNOWN")
            self.send(row)
            message.return_value.send.assert_called_once()
        self.assertEqual(row.attempts.count(), 1)
        self.assertEqual(row.attempts.get().error_code, "OUTCOME_UNKNOWN")
