"""Tests for verifying that hidden test case details are not leaked to users."""

import pytest
import json


@pytest.mark.security
def test_hidden_tests_exist_in_response(api_client, valid_token, incorrect_solution):
    """Test that hidden tests are included in the response count."""
    response = api_client['submit'](
        code=incorrect_solution,
        function_name='two_sum',
        token=valid_token
    )
    
    assert response.status_code == 200
    data = response.json()
    
    # Should have 7 total tests (4 public + 3 hidden)
    assert data['total'] == 7
    assert len(data['test_results']) == 7


@pytest.mark.security
def test_hidden_test_details_not_sent(api_client, valid_token, incorrect_solution):
    """
    Test that hidden test case details (expected, actual, error) are NOT sent to client.
    This is a critical security test.
    """
    response = api_client['submit'](
        code=incorrect_solution,
        function_name='two_sum',
        token=valid_token
    )
    
    assert response.status_code == 200
    data = response.json()
    
    # Check each test result
    for test_result in data['test_results']:
        test_number = test_result.get('test_number')
        is_hidden = test_result.get('is_hidden', False)
        
        if is_hidden or test_number >= 5:  # Tests 5, 6, 7 are hidden
            # Hidden tests should only have these fields
            allowed_fields = {'test_number', 'description', 'passed', 'is_hidden'}
            actual_fields = set(test_result.keys())
            
            # Verify no sensitive data is present
            assert 'expected' not in test_result, f"Test {test_number}: 'expected' should not be sent for hidden tests"
            assert 'actual' not in test_result, f"Test {test_number}: 'actual' should not be sent for hidden tests"
            assert 'error' not in test_result, f"Test {test_number}: 'error' should not be sent for hidden tests"
            assert 'stdout' not in test_result, f"Test {test_number}: 'stdout' should not be sent for hidden tests"
            assert 'stderr' not in test_result, f"Test {test_number}: 'stderr' should not be sent for hidden tests"
            
            # Verify only allowed fields are present
            assert actual_fields <= allowed_fields, f"Test {test_number}: Unexpected fields in hidden test: {actual_fields - allowed_fields}"
            
            # Verify description doesn't leak information
            assert test_result['description'] == 'Hidden test case'

@pytest.mark.security

def test_public_test_details_are_sent(api_client, valid_token, incorrect_solution):
    """Test that public test case details ARE sent to client for debugging."""
    response = api_client['submit'](
        code=incorrect_solution,
        function_name='two_sum',
        token=valid_token
    )
    
    assert response.status_code == 200
    data = response.json()
    
    # Check first 4 tests (public tests)
    public_tests = [tr for tr in data['test_results'] if tr['test_number'] <= 4]
    
    assert len(public_tests) == 4
    
    for test_result in public_tests:
        # Public tests that fail should include detailed feedback
        if not test_result.get('passed', False):
            assert 'expected' in test_result, f"Public test {test_result['test_number']} should include 'expected'"
            assert 'actual' in test_result, f"Public test {test_result['test_number']} should include 'actual'"

@pytest.mark.security

def test_hidden_test_pass_fail_status_is_sent(api_client, valid_token, correct_solution):
    """Test that we DO send pass/fail status for hidden tests (just not the details)."""
    response = api_client['submit'](
        code=correct_solution,
        function_name='two_sum',
        token=valid_token
    )
    
    assert response.status_code == 200
    data = response.json()
    
    # Find hidden tests
    hidden_tests = [tr for tr in data['test_results'] if tr.get('is_hidden', False) or tr['test_number'] >= 5]
    
    assert len(hidden_tests) == 3
    
    for test_result in hidden_tests:
        # Should have pass/fail status
        assert 'passed' in test_result
        assert isinstance(test_result['passed'], bool)
        # With correct solution, all should pass
        assert test_result['passed'] is True

@pytest.mark.security

def test_cannot_reverse_engineer_hidden_tests(api_client, valid_token):
    """
    Test that even with multiple submissions, hidden test details cannot be extracted.
    """
    test_solutions = [
        'def two_sum(nums, target):\n    return [0, 0]',
        'def two_sum(nums, target):\n    return [0, 1]',
        'def two_sum(nums, target):\n    return [1, 1]',
    ]
    
    for solution in test_solutions:
        response = api_client['submit'](
            code=solution,
            function_name='two_sum',
            token=valid_token
        )
        
        assert response.status_code == 200
        data = response.json()
        
        # Even across multiple submissions, hidden test details should never be sent
        for test_result in data['test_results']:
            if test_result.get('is_hidden', False):
                assert 'expected' not in test_result
                assert 'actual' not in test_result
                assert 'error' not in test_result
@pytest.mark.security


def test_syntax_error_doesnt_leak_hidden_tests(api_client, valid_token):
    """Test that syntax errors don't cause hidden test details to leak."""
    invalid_code = '''def two_sum(nums, target)
    return [0, 0]  # Missing colon
'''
    
    response = api_client['submit'](
        code=invalid_code,
        function_name='two_sum',
        token=valid_token
    )
    
    # Should return an error response
    assert response.status_code == 400
    data = response.json()
    
    # Should indicate syntax error
    assert data['success'] is False
    assert 'syntax_error' in data or 'error' in data
@pytest.mark.security


def test_hidden_flag_consistency(api_client, valid_token, incorrect_solution):
    """Test that is_hidden flag is consistently set for hidden tests."""
    response = api_client['submit'](
        code=incorrect_solution,
        function_name='two_sum',
        token=valid_token
    )
    
    assert response.status_code == 200
    data = response.json()
    
    for test_result in data['test_results']:
        test_number = test_result['test_number']
        is_hidden = test_result.get('is_hidden', False)
        
        # Tests 1-4 should be public (is_hidden=False)
        # Tests 5-7 should be hidden (is_hidden=True)
        if test_number <= 4:
            assert is_hidden is False, f"Test {test_number} should be public"
        else:
            assert is_hidden is True, f"Test {test_number} should be hidden"
