"""
Notification Service Tests - Providers.
"""
import pytest
from unittest.mock import patch, MagicMock

from apps.services.notification.providers import ProviderResponse
from apps.services.notification.providers.sms import SMSProvider
from apps.services.notification.providers.email import EmailProvider
from apps.services.notification.providers.panel import PanelProvider
from apps.services.notification.models import NotificationChannel


class TestSMSProvider:
    """Tests for SMS provider."""
    
    @pytest.fixture
    def provider(self):
        """Create SMS provider instance."""
        return SMSProvider()
    
    def test_validate_valid_phone_09(self, provider):
        """Test validation of 09xxxxxxxxx format."""
        assert provider.validate_recipient('09123456789') is True
    
    def test_validate_valid_phone_98(self, provider):
        """Test validation of 98xxxxxxxxxx format."""
        assert provider.validate_recipient('989123456789') is True
    
    def test_validate_valid_phone_plus98(self, provider):
        """Test validation of +98xxxxxxxxxx format."""
        assert provider.validate_recipient('+989123456789') is True
    
    def test_validate_invalid_phone(self, provider):
        """Test validation of invalid phone numbers."""
        assert provider.validate_recipient('12345') is False
        assert provider.validate_recipient('') is False
        assert provider.validate_recipient(None) is False
        assert provider.validate_recipient('abc') is False
    
    def test_normalize_phone_09(self, provider):
        """Test phone normalization from 09 format."""
        assert provider._normalize_phone('09123456789') == '989123456789'
    
    def test_normalize_phone_98(self, provider):
        """Test phone normalization from 98 format."""
        assert provider._normalize_phone('989123456789') == '989123456789'
    
    def test_normalize_phone_plus98(self, provider):
        """Test phone normalization from +98 format."""
        assert provider._normalize_phone('+989123456789') == '989123456789'
    
    @patch('apps.services.notification.providers.sms.requests.post')
    def test_send_success(self, mock_post, provider):
        """Test successful SMS send."""
        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            'status': 1,
            'data': {'messageId': '12345'}
        }
        mock_response.content = b'{"status": 1}'
        mock_post.return_value = mock_response
        
        # Mock settings
        with patch.object(provider, 'api_key', 'test_key'):
            with patch.object(provider, 'line_number', '30004505'):
                result = provider.send('09123456789', 'Test message')
        
        assert result.success is True
        assert result.message_id == '12345'
    
    @patch('apps.services.notification.providers.sms.requests.post')
    def test_send_failure(self, mock_post, provider):
        """Test failed SMS send."""
        mock_response = MagicMock()
        mock_response.status_code = 400
        mock_response.json.return_value = {
            'status': 0,
            'message': 'Invalid API key'
        }
        mock_response.content = b'{"status": 0}'
        mock_post.return_value = mock_response
        
        with patch.object(provider, 'api_key', 'test_key'):
            with patch.object(provider, 'line_number', '30004505'):
                result = provider.send('09123456789', 'Test message')
        
        assert result.success is False
        assert 'Invalid API key' in result.error
    
    def test_send_invalid_phone(self, provider):
        """Test send with invalid phone number."""
        with patch.object(provider, 'api_key', 'test_key'):
            with patch.object(provider, 'line_number', '30004505'):
                result = provider.send('invalid', 'Test message')
        
        assert result.success is False
        assert 'Invalid phone number' in result.error
    
    def test_send_not_configured(self, provider):
        """Test send when not configured."""
        provider.api_key = None
        result = provider.send('09123456789', 'Test message')
        
        assert result.success is False
        assert 'not configured' in result.error


class TestEmailProvider:
    """Tests for Email provider."""
    
    @pytest.fixture
    def provider(self):
        """Create Email provider instance."""
        return EmailProvider()
    
    def test_validate_valid_email(self, provider):
        """Test validation of valid email addresses."""
        assert provider.validate_recipient('test@example.com') is True
        assert provider.validate_recipient('user.name@domain.co.ir') is True
        assert provider.validate_recipient('user+tag@example.org') is True
    
    def test_validate_invalid_email(self, provider):
        """Test validation of invalid email addresses."""
        assert provider.validate_recipient('invalid') is False
        assert provider.validate_recipient('') is False
        assert provider.validate_recipient(None) is False
        assert provider.validate_recipient('@example.com') is False
        assert provider.validate_recipient('user@') is False
    
    @patch('apps.services.notification.providers.email.send_mail')
    def test_send_success(self, mock_send_mail, provider):
        """Test successful email send."""
        mock_send_mail.return_value = 1
        
        with patch.object(provider, 'from_email', 'noreply@test.com'):
            with patch.object(provider, 'email_host', 'smtp.test.com'):
                result = provider.send(
                    'test@example.com',
                    'Test content',
                    subject='Test Subject'
                )
        
        assert result.success is True
        mock_send_mail.assert_called_once()
    
    @patch('apps.services.notification.providers.email.send_mail')
    def test_send_failure(self, mock_send_mail, provider):
        """Test failed email send."""
        mock_send_mail.return_value = 0
        
        with patch.object(provider, 'from_email', 'noreply@test.com'):
            with patch.object(provider, 'email_host', 'smtp.test.com'):
                result = provider.send(
                    'test@example.com',
                    'Test content',
                    subject='Test Subject'
                )
        
        assert result.success is False
    
    def test_send_invalid_email(self, provider):
        """Test send with invalid email."""
        with patch.object(provider, 'from_email', 'noreply@test.com'):
            with patch.object(provider, 'email_host', 'smtp.test.com'):
                result = provider.send('invalid', 'Test content')
        
        assert result.success is False
        assert 'Invalid email' in result.error
    
    def test_send_not_configured(self, provider):
        """Test send when not configured."""
        provider.from_email = None
        result = provider.send('test@example.com', 'Test content')
        
        assert result.success is False
        assert 'not configured' in result.error


class TestPanelProvider:
    """Tests for Panel provider."""
    
    @pytest.fixture
    def provider(self):
        """Create Panel provider instance."""
        return PanelProvider()
    
    def test_validate_valid_user_id_int(self, provider):
        """Test validation of integer user ID."""
        assert provider.validate_recipient('123') is True
    
    def test_validate_valid_user_id_uuid(self, provider):
        """Test validation of UUID user ID."""
        assert provider.validate_recipient('550e8400-e29b-41d4-a716-446655440000') is True
    
    def test_validate_invalid_user_id(self, provider):
        """Test validation of invalid user IDs."""
        assert provider.validate_recipient('') is False
        assert provider.validate_recipient(None) is False
        assert provider.validate_recipient('not-a-uuid-or-int') is False
    
    def test_send_success(self, provider):
        """Test successful panel notification."""
        result = provider.send('123', 'Test notification')
        
        assert result.success is True
        assert result.raw_response == {'stored': True}
    
    def test_send_invalid_recipient(self, provider):
        """Test send with invalid recipient."""
        result = provider.send('invalid!', 'Test notification')
        
        assert result.success is False
