import pytest
from unittest.mock import patch, Mock
from app import create_app, db
from app.models import User, Folder, AIRuleCache
from bs4 import BeautifulSoup

class TestAIRuleUserFlow:
    """Test cases for the complete AI rule generation user flow."""
    
    @pytest.fixture
    def app(self):
        """Create and configure a test app."""
        app = create_app('testing')
        
        with app.app_context():
            db.create_all()
            yield app
            db.drop_all()
            
    @pytest.fixture
    def client(self, app):
        """Create a test client."""
        return app.test_client()
        
    @pytest.fixture
    def user(self, app):
        """Create a test user."""
        with app.app_context():
            user = User(
                first_name='Test',
                last_name='User',
                email='test@example.com',
                password_hash='hashed_password'
            )
            db.session.add(user)
            db.session.commit()
            return user
            
    def test_folder_creation_modal_with_ai_controls(self, client, user):
        """Test that folder creation modal includes AI controls."""
        # Simulate logged-in user by setting session
        with client.session_transaction() as sess:
            sess['user_id'] = user.id
            
        response = client.get('/api/folders/new')
        
        assert response.status_code == 200
        # Check that AI controls are present
        assert b'Generate Rule' in response.data
        assert b'Multiple Options' in response.data
        assert b'generate-rule' in response.data
        
    def test_ai_rule_generation_in_modal(self, client, user):
        """Test AI rule generation within the folder creation modal."""
        # Simulate logged-in user by setting session
        with client.session_transaction() as sess:
            sess['user_id'] = user.id
            
        with patch('app.routes.folders.ai_service') as mock_ai_service:
            # Mock AI service response
            mock_ai_service.generate_multiple_rules.return_value = (
                [{'text': "Move emails from 'boss@company.com' to this folder", 'quality_score': 85}],
                {'total_generated': 1}
            )
            
            # Simulate AI rule generation request
            response = client.post('/api/folders/generate-rule', data={
                'folder_name': 'Work',
                'folder_type': 'destination',
                'rule_type': 'multiple'
            })
            
            assert response.status_code == 200
            # Check that the response contains AI-generated rule
            assert b'Move emails from' in response.data
            assert b'generated-rule-text' in response.data
            assert b'85%' in response.data
            
    def test_multiple_rule_options_in_modal(self, client, user):
        """Test multiple rule options within the folder creation modal."""
        # Simulate logged-in user by setting session
        with client.session_transaction() as sess:
            sess['user_id'] = user.id
            
        with patch('app.routes.folders.ai_service') as mock_ai_service:
            # Mock AI service response
            mock_ai_service.generate_multiple_rules.return_value = (
                [
                    {'text': 'Move emails from boss@company.com', 'quality_score': 85},
                    {'text': 'Move emails with urgent subject', 'quality_score': 75},
                    {'text': 'Move emails from team members', 'quality_score': 70}
                ],
                {'total_generated': 3}
            )
            
            # Simulate multiple rule generation request
            response = client.post('/api/folders/generate-rule', data={
                'folder_name': 'Work',
                'folder_type': 'destination',
                'rule_type': 'multiple'
            })
            
            assert response.status_code == 200
            # Check that multiple rules are displayed
            assert b'Move emails from boss@company.com' in response.data
            assert b'Move emails with urgent subject' in response.data
            assert b'Move emails from team members' in response.data
            assert b'85%' in response.data
            assert b'75%' in response.data
            assert b'70%' in response.data
            
    def test_folder_creation_with_ai_rule(self, client, user):
        """Test folder creation using AI-generated rule."""
        # Simulate logged-in user by setting session
        with client.session_transaction() as sess:
            sess['user_id'] = user.id
            
        with patch('app.routes.folders.ai_service') as mock_ai_service:
            # Mock AI service response
            mock_ai_service.generate_multiple_rules.return_value = (
                [{'text': "Move emails from 'newsletter@company.com' to this folder", 'quality_score': 90}],
                {'total_generated': 1}
            )
            
            # First, generate the rule
            response = client.post('/api/folders/generate-rule', data={
                'folder_name': 'Newsletters',
                'folder_type': 'destination',
                'rule_type': 'multiple'
            })
            
            assert response.status_code == 200
            
            # Then create folder with the generated rule
            # We need to extract the rule from the response and use it
            soup = BeautifulSoup(response.data, 'html.parser')
            rule_text = soup.find(id='generated-rule-text').text.strip()
            
            response = client.post('/api/folders', data={
                'name': 'Newsletters',
                'rule_text': rule_text,
                'priority': '0'
            })
            
            assert response.status_code == 201
            # Check that folder was created
            folder = Folder.query.filter_by(name='Newsletters', user_id=user.id).first()
            assert folder is not None
            assert folder.rule_text == rule_text
            
    def test_rule_quality_assessment(self, client, user):
        """Test rule quality assessment functionality."""
        # Simulate logged-in user by setting session
        with client.session_transaction() as sess:
            sess['user_id'] = user.id
            
        with patch('app.routes.folders.ai_service') as mock_ai_service:
            # Mock AI service response
            mock_ai_service.assess_rule_quality.return_value = {
                'score': 75,
                'grade': 'good',
                'feedback': 'Good rule with room for improvement',
                'assessed_at': '2023-01-01T00:00:00'
            }
            
            response = client.post('/api/folders/assess-rule', data={
                'rule_text': 'Move emails from boss@company.com to this folder',
                'folder_name': 'Work',
                'folder_type': 'destination'
            })
            
            assert response.status_code == 200
            # Check that quality assessment is displayed
            assert b'75%' in response.data
            assert b'generated-rule-text' in response.data
            
    def test_error_handling_in_modal(self, client, user):
        """Test error handling within the modal."""
        # Simulate logged-in user by setting session
        with client.session_transaction() as sess:
            sess['user_id'] = user.id
            
        # Test with invalid inputs
        response = client.post('/api/folders/generate-rule', data={
            'folder_type': 'destination',
            'rule_type': 'multiple'
        })
        
        assert response.status_code == 200
        # Check that error is displayed in modal format
        assert b'Folder name is required' in response.data
        
    def test_fallback_rule_generation(self, client, user):
        """Test fallback rule generation when AI service fails."""
        # Simulate logged-in user by setting session
        with client.session_transaction() as sess:
            sess['user_id'] = user.id
            
        with patch('app.routes.folders.ai_service') as mock_ai_service:
            # Mock AI service failure
            mock_ai_service.generate_multiple_rules.return_value = (None, {'error': 'Service unavailable'})
            mock_ai_service.get_fallback_rule.return_value = 'Move emails containing "Work" to this folder'
            
            response = client.post('/api/folders/generate-rule', data={
                'folder_name': 'Work',
                'folder_type': 'destination',
                'rule_type': 'multiple'
            })
            
            assert response.status_code == 200
            # Check that fallback rule is displayed
            assert b'Move emails containing "Work" to this folder' in response.data
            assert b'AI service unavailable' in response.data
            
    def test_cache_usage_indicator(self, client, user):
        """Test that cache usage is properly indicated."""
        # Simulate logged-in user by setting session
        with client.session_transaction() as sess:
            sess['user_id'] = user.id
            
        # Create a cache entry
        from datetime import datetime
        cache_entry = AIRuleCache(
            user_id=user.id,
            folder_name='Work',
            folder_type='destination',
            rule_text='Cached rule',
            rule_metadata={'quality_score': 90},
            cache_key='test-key',
            expires_at=datetime(2023, 12, 31, 23, 59, 59),  # Future expiration
            is_active=True
        )
        db.session.add(cache_entry)
        db.session.commit()
        
        with patch('app.routes.folders.ai_service') as mock_ai_service:
            # Make AI service return different rule to verify cache is used
            mock_ai_service.generate_single_rule.return_value = (
                'New rule',
                {'quality_score': 95}
            )
            
            response = client.post('/api/folders/generate-rule', data={
                'folder_name': 'Work',
                'folder_type': 'destination',
                'rule_type': 'single'
            })
            
            assert response.status_code == 200
            # Check that cached rule is used
            assert b'Using cached rule' in response.data
            assert b'Cached rule' in response.data
            # New rule should not appear
            assert b'New rule' not in response.data
            
    def test_keyboard_navigation_support(self, client, user):
        """Test that keyboard navigation is supported."""
        # Simulate logged-in user by setting session
        with client.session_transaction() as sess:
            sess['user_id'] = user.id
            
        response = client.get('/api/folders/new')
        
        assert response.status_code == 200
        # Check that buttons have proper ARIA labels
        assert b'aria-label' in response.data
        assert b'Generate AI-powered email rule' in response.data
        assert b'Generate multiple AI-powered email rule options' in response.data
        
    def test_screen_reader_support(self, client, user):
        """Test that screen reader support is implemented."""
        # Simulate logged-in user by setting session
        with client.session_transaction() as sess:
            sess['user_id'] = user.id
            
        with patch('app.routes.folders.ai_service') as mock_ai_service:
            # Mock AI service response
            mock_ai_service.generate_single_rule.return_value = (
                "Move emails from 'boss@company.com' to this folder",
                {'quality_score': 85, 'model_used': 'test-model'}
            )
            
            response = client.post('/api/folders/generate-rule', data={
                'folder_name': 'Work',
                'folder_type': 'destination',
                'rule_type': 'single'
            })
            
            assert response.status_code == 200
            # Check that screen reader support is present
            assert b'role="status"' in response.data
            assert b'aria-live="polite"' in response.data
            assert b'sr-only' in response.data
            
    def test_loading_states(self, client, user):
        """Test that loading states are properly handled."""
        # Simulate logged-in user by setting session
        with client.session_transaction() as sess:
            sess['user_id'] = user.id
            
        response = client.get('/api/folders/new')
        
        assert response.status_code == 200
        # Check that loading states are configured
        assert b'data-loading-disable' in response.data
        assert b'data-loading-class' in response.data
        assert b'loading-spinner' in response.data