import pytest
from app.models import User, Folder
from app import db
import uuid
from bs4 import BeautifulSoup

def test_index_route(client, app, mock_user):
    """Test the index route requires authentication."""
    response = client.get('/')
    # Should redirect to login page
    assert response.status_code == 302
    assert '/login' in response.location

def test_index_route_authenticated(authenticated_client, app, mock_user):
    """Test the index route works for authenticated users."""
    response = authenticated_client.get('/')
    assert response.status_code == 200
    # Check if the page contains expected elements
    assert b'Email Organizer' in response.data
    assert b'Folders' in response.data
    assert b'Test User' in response.data  # Should show user's name

def test_add_folder_route(authenticated_client, mock_user):
    """Test the add folder API endpoint."""
    # Get initial count of folders for the user
    initial_folder_count = Folder.query.count()
    
    # Send form data (URL encoded) instead of JSON
    response = authenticated_client.post('/api/folders',
                           data={'name': 'Test Folder', 'rule_text': 'Test rule something ok yes'},
                           content_type='application/x-www-form-urlencoded')
    
    # Verify the response status is 201 Created
    assert response.status_code == 201
    
    # Verify that the number of folders has increased
    final_folder_count = Folder.query.count()
    assert final_folder_count > initial_folder_count
    
    # Verify the folder belongs to the authenticated user
    created_folder = Folder.query.filter_by(name='Test Folder').first()
    assert created_folder.user_id == mock_user.id

# Validation failure tests
def test_add_folder_validation_failure_empty_name(authenticated_client, mock_user):
    """Test validation failure when folder name is empty."""
    response = authenticated_client.post('/api/folders',
                           data={'name': '', 'rule_text': 'Test rule something ok yes'},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    # Check that the specific error message is present
    error_text = soup.find(string='Folder name is required')
    assert error_text is not None
    # Check that the input field has the error class
    name_input = soup.find('input', {'name': 'name'})
    assert name_input is not None
    assert 'input-error' in name_input.get('class', [])

def test_add_folder_validation_failure_short_name(authenticated_client, mock_user):
    """Test validation failure when folder name is too short."""
    response = authenticated_client.post('/api/folders',
                           data={'name': 'ab', 'rule_text': 'Test rule something ok yes'},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text = soup.find(string='Folder name must be at least 3 characters')
    assert error_text is not None

def test_add_folder_validation_failure_long_name(authenticated_client, mock_user):
    """Test validation failure when folder name is too long."""
    long_name = 'a' * 51
    response = authenticated_client.post('/api/folders',
                           data={'name': long_name, 'rule_text': 'Test rule something ok yes'},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text = soup.find(string='Folder name must be less than 50 characters')
    assert error_text is not None

def test_add_folder_validation_failure_empty_rule(authenticated_client, mock_user):
    """Test validation failure when rule text is empty."""
    response = authenticated_client.post('/api/folders',
                           data={'name': 'Test Folder', 'rule_text': ''},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text = soup.find(string='Rule text is required')
    assert error_text is not None

def test_add_folder_validation_failure_short_rule(authenticated_client, mock_user):
    """Test validation failure when rule text is too short."""
    response = authenticated_client.post('/api/folders',
                           data={'name': 'Test Folder', 'rule_text': 'short'},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text = soup.find(string='Rule text must be at least 10 characters')
    assert error_text is not None

def test_add_folder_validation_failure_long_rule(authenticated_client, mock_user):
    """Test validation failure when rule text is too long."""
    long_rule = 'a' * 201
    response = authenticated_client.post('/api/folders',
                           data={'name': 'Test Folder', 'rule_text': long_rule},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text = soup.find(string='Rule text must be less than 200 characters')
    assert error_text is not None

def test_add_folder_validation_multiple_errors(authenticated_client, mock_user):
    """Test validation failure with multiple errors."""
    response = authenticated_client.post('/api/folders',
                           data={'name': 'ab', 'rule_text': 'short'},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text1 = soup.find(string='Folder name must be at least 3 characters')
    error_text2 = soup.find(string='Rule text must be at least 10 characters')
    assert error_text1 is not None
    assert error_text2 is not None

# Edit folder validation failure tests
def test_edit_folder_validation_failure_empty_name(authenticated_client, mock_folder):
    """Test validation failure when folder name is empty during edit."""
    response = authenticated_client.put(f'/api/folders/{mock_folder.id}',
                           data={'name': '', 'rule_text': 'Test rule something ok yes'},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text = soup.find(string='Folder name is required')
    assert error_text is not None

def test_edit_folder_validation_failure_short_name(authenticated_client, mock_folder):
    """Test validation failure when folder name is too short during edit."""
    response = authenticated_client.put(f'/api/folders/{mock_folder.id}',
                           data={'name': 'ab', 'rule_text': 'Test rule something ok yes'},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text = soup.find(string='Folder name must be at least 3 characters')
    assert error_text is not None

def test_edit_folder_validation_failure_long_name(authenticated_client, mock_folder):
    """Test validation failure when folder name is too long during edit."""
    long_name = 'a' * 51
    response = authenticated_client.put(f'/api/folders/{mock_folder.id}',
                           data={'name': long_name, 'rule_text': 'Test rule something ok yes'},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text = soup.find(string='Folder name must be less than 50 characters')
    assert error_text is not None

def test_edit_folder_validation_failure_empty_rule(authenticated_client, mock_folder):
    """Test validation failure when rule text is empty during edit."""
    response = authenticated_client.put(f'/api/folders/{mock_folder.id}',
                           data={'name': 'Test Folder', 'rule_text': ''},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text = soup.find(string='Rule text is required')
    assert error_text is not None

def test_edit_folder_validation_failure_short_rule(authenticated_client, mock_folder):
    """Test validation failure when rule text is too short during edit."""
    response = authenticated_client.put(f'/api/folders/{mock_folder.id}',
                           data={'name': 'Test Folder', 'rule_text': 'short'},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text = soup.find(string='Rule text must be at least 10 characters')
    assert error_text is not None

def test_edit_folder_validation_failure_long_rule(authenticated_client, mock_folder):
    """Test validation failure when rule text is too long during edit."""
    long_rule = 'a' * 201
    response = authenticated_client.put(f'/api/folders/{mock_folder.id}',
                           data={'name': 'Test Folder', 'rule_text': long_rule},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text = soup.find(string='Rule text must be less than 200 characters')
    assert error_text is not None

def test_edit_folder_validation_multiple_errors(authenticated_client, mock_folder):
    """Test validation failure with multiple errors during edit."""
    response = authenticated_client.put(f'/api/folders/{mock_folder.id}',
                           data={'name': 'ab', 'rule_text': 'short'},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    soup = BeautifulSoup(response.data, 'html.parser')
    error_text1 = soup.find(string='Folder name must be at least 3 characters')
    error_text2 = soup.find(string='Rule text must be at least 10 characters')
    assert error_text1 is not None
    assert error_text2 is not None

# Dialog close tests
def test_add_folder_success_closes_dialog(authenticated_client, mock_user):
    """Test that successful folder creation triggers dialog close."""
    response = authenticated_client.post('/api/folders',
                           data={'name': 'Test Folder', 'rule_text': 'Test rule something ok yes'},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 201
    # Check for close-modal trigger in response headers
    assert 'HX-Trigger' in response.headers
    assert 'close-modal' in response.headers['HX-Trigger']

def test_edit_folder_success_closes_dialog(authenticated_client, mock_folder):
    """Test that successful folder update triggers dialog close."""
    response = authenticated_client.put(f'/api/folders/{mock_folder.id}',
                           data={'name': 'Updated Folder', 'rule_text': 'Updated rule text'},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    # Check for close-modal trigger in response headers
    assert 'HX-Trigger' in response.headers
    assert 'close-modal' in response.headers['HX-Trigger']

# Content matching tests
def test_add_folder_content_matches_submission(authenticated_client, mock_user):
    """Test that submitted folder content matches what was sent."""
    test_name = 'Test Folder Content'
    test_rule = 'Test rule content matching submission'
    test_priority = '1'
    
    response = authenticated_client.post('/api/folders',
                           data={'name': test_name, 'rule_text': test_rule, 'priority': test_priority},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 201
    
    # Verify the folder was created with correct content
    created_folder = Folder.query.filter_by(name=test_name).first()
    assert created_folder is not None
    assert created_folder.name == test_name.strip()
    assert created_folder.rule_text == test_rule.strip()
    assert created_folder.priority == int(test_priority)
    assert created_folder.user_id == mock_user.id

def test_edit_folder_content_matches_submission(authenticated_client, mock_folder):
    """Test that updated folder content matches what was sent."""
    test_name = 'Updated Folder Content'
    test_rule = 'Updated rule content matching submission'
    test_priority = '-1'
    
    response = authenticated_client.put(f'/api/folders/{mock_folder.id}',
                           data={'name': test_name, 'rule_text': test_rule, 'priority': test_priority},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    
    # Verify the folder was updated with correct content
    updated_folder = Folder.query.filter_by(id=mock_folder.id).first()
    assert updated_folder is not None
    assert updated_folder.name == test_name.strip()
    assert updated_folder.rule_text == test_rule.strip()
    assert updated_folder.priority == int(test_priority)

def test_add_folder_content_whitespace_handling(authenticated_client, mock_user):
    """Test that whitespace is properly handled in submitted content."""
    test_name = '  Test Folder With Whitespace  '
    test_rule = '  Test rule with whitespace around it  '
    test_priority = '0'
    
    response = authenticated_client.post('/api/folders',
                           data={'name': test_name, 'rule_text': test_rule, 'priority': test_priority},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 201
    
    # Verify the folder was created with properly trimmed content
    created_folder = Folder.query.filter_by(name='Test Folder With Whitespace').first()
    assert created_folder is not None
    assert created_folder.name == 'Test Folder With Whitespace'  # Should be trimmed
    assert created_folder.rule_text == 'Test rule with whitespace around it'  # Should be trimmed
    assert created_folder.priority == int(test_priority)

def test_edit_folder_content_whitespace_handling(authenticated_client, mock_folder):
    """Test that whitespace is properly handled in updated content."""
    test_name = '  Updated Folder With Whitespace  '
    test_rule = '  Updated rule with whitespace around it  '
    test_priority = '1'
    
    response = authenticated_client.put(f'/api/folders/{mock_folder.id}',
                           data={'name': test_name, 'rule_text': test_rule, 'priority': test_priority},
                           content_type='application/x-www-form-urlencoded')
    
    assert response.status_code == 200
    
    # Verify the folder was updated with properly trimmed content
    updated_folder = Folder.query.filter_by(id=mock_folder.id).first()
    assert updated_folder is not None
    assert updated_folder.name == 'Updated Folder With Whitespace'  # Should be trimmed
    assert updated_folder.rule_text == 'Updated rule with whitespace around it'  # Should be trimmed
    assert updated_folder.priority == int(test_priority)
    
def test_toggle_folder_organize_enabled(authenticated_client, mock_folder):
    """Test toggling the organize_enabled flag for a folder."""
    # Verify initial state is True (default)
    assert mock_folder.organize_enabled is True
    
    # Toggle the flag
    response = authenticated_client.put(f'/api/folders/{mock_folder.id}/type', data={'folder_type': 'ignore'}, content_type='application/x-www-form-urlencoded')
    
    # Should return 200 OK
    assert response.status_code == 200
    
    # Verify the folder was updated in the database
    updated_folder = Folder.query.filter_by(id=mock_folder.id).first()
    assert updated_folder is not None
    assert updated_folder.folder_type == 'ignore'
    
    # Toggle back to make sure it works both ways
    response2 = authenticated_client.put(f'/api/folders/{mock_folder.id}/type', data={'folder_type': 'tidy'}, content_type='application/x-www-form-urlencoded')
    
    # Should return 200 OK
    assert response2.status_code == 200
    
    # Verify the folder was updated in the database again
    updated_folder2 = Folder.query.filter_by(id=mock_folder.id).first()
    assert updated_folder2 is not None
    assert updated_folder2.folder_type == 'tidy'

def test_toggle_folder_organize_enabled_not_found(authenticated_client, mock_user):
    """Test toggling organize_enabled flag for a non-existent folder."""
    # Try to toggle a folder that doesn't exist
    response = authenticated_client.put('/api/folders/999/toggle')
    
    # Should return 404 Not Found
    assert response.status_code == 404
    
def test_toggle_folder_organize_enabled_unauthorized(authenticated_client, mock_user, app):
    """Test toggling organize_enabled flag for a folder that doesn't belong to the user."""
    # Create a folder that belongs to a different user
    other_user = User(email='other@example.com', first_name='Other', last_name='User')
    other_user.set_password('password')
    
    with app.app_context():
        db.session.add(other_user)
        db.session.commit()
        
        # Create a folder for the other user
        other_folder = Folder(
            user_id=other_user.id,
            name='Other User Folder',
            rule_text='Test rule text'
        )
        db.session.add(other_folder)
        db.session.commit()
        
        # Try to toggle the flag for the folder that doesn't belong to authenticated user
        response = authenticated_client.put(f'/api/folders/{other_folder.id}/toggle')
        
        # Should return 404 Not Found (folder not found due to authorization check)
        assert response.status_code == 404