"""
Unit tests for app/services/email_service.py.

The core property under test: send_email() must NEVER raise, regardless
of configuration state or SMTP failure — it always returns a bool. This
is what lets the calling notification_service safely treat email as a
best-effort side channel.
"""

from unittest.mock import MagicMock, patch

from app.services.email_service import build_feasibility_change_email, send_email


class TestSendEmailSafeFailure:
    def test_returns_false_when_email_disabled(self):
        with patch("app.services.email_service.settings") as mock_settings:
            mock_settings.EMAIL_ENABLED = False
            result = send_email("farmer@example.com", "Subject", "Body")
        assert result is False

    def test_returns_false_when_smtp_not_configured(self):
        with patch("app.services.email_service.settings") as mock_settings:
            mock_settings.EMAIL_ENABLED = True
            mock_settings.SMTP_HOST = ""
            mock_settings.SMTP_USERNAME = ""
            result = send_email("farmer@example.com", "Subject", "Body")
        assert result is False

    def test_returns_false_on_smtp_exception_not_raises(self):
        with patch("app.services.email_service.settings") as mock_settings, \
             patch("app.services.email_service.smtplib.SMTP") as mock_smtp:
            mock_settings.EMAIL_ENABLED = True
            mock_settings.SMTP_HOST = "smtp.example.com"
            mock_settings.SMTP_USERNAME = "user"
            mock_settings.SMTP_PASSWORD = "pass"
            mock_settings.SMTP_PORT = 587
            mock_settings.SMTP_USE_TLS = True
            mock_settings.EMAIL_FROM_ADDRESS = "noreply@example.com"
            mock_settings.EMAIL_FROM_NAME = "Test"

            mock_smtp.side_effect = ConnectionRefusedError("connection refused")

            result = send_email("farmer@example.com", "Subject", "Body")

        assert result is False

    def test_returns_true_on_successful_send(self):
        with patch("app.services.email_service.settings") as mock_settings, \
             patch("app.services.email_service.smtplib.SMTP") as mock_smtp_class:
            mock_settings.EMAIL_ENABLED = True
            mock_settings.SMTP_HOST = "smtp.example.com"
            mock_settings.SMTP_USERNAME = "user"
            mock_settings.SMTP_PASSWORD = "pass"
            mock_settings.SMTP_PORT = 587
            mock_settings.SMTP_USE_TLS = True
            mock_settings.EMAIL_FROM_ADDRESS = "noreply@example.com"
            mock_settings.EMAIL_FROM_NAME = "Test"

            mock_server = MagicMock()
            mock_smtp_class.return_value.__enter__.return_value = mock_server

            result = send_email("farmer@example.com", "Subject", "Body")

        assert result is True
        mock_server.sendmail.assert_called_once()


class TestBuildFeasibilityChangeEmail:
    def test_first_analysis_phrasing(self):
        subject, text, html = build_feasibility_change_email("rice", "thanjavur", None, "suitable")
        assert "rice" in subject.lower()
        assert "is now classified as" in text

    def test_changed_status_phrasing(self):
        subject, text, html = build_feasibility_change_email(
            "rice", "thanjavur", "suitable", "risky"
        )
        assert "changed from" in text
        assert "suitable" in text
        assert "risky" in text
