"""Tests for the submission flow and validation."""

import pytest
import os
import sys
from pathlib import Path

# Add src to path
sys.path.insert(0, str(Path(__file__).parent.parent / 'src'))


def test_correct_solution_passes_all_tests(api_client, valid_token, correct_solution):
    """Test that a correct solution passes all tests (public and hidden)."""
    response = api_client['submit'](
        code=correct_solution,
        function_name='two_sum',
        token=valid_token
    )
    
    assert response.status_code == 200
    data = response.json()
    
    assert data['success'] is True
    assert data['passed'] == 7
    assert data['failed'] == 0
    assert data['total'] == 7


def test_incorrect_solution_fails_tests(api_client, valid_token, incorrect_solution):
    """Test that an incorrect solution fails tests appropriately."""
    response = api_client['submit'](
        code=incorrect_solution,
        function_name='two_sum',
        token=valid_token
    )
    
    assert response.status_code == 200
    data = response.json()
    
    assert data['success'] is False
    assert data['failed'] > 0
    assert data['passed'] < data['total']


def test_missing_function_name_error(api_client, valid_token, correct_solution):
    """Test that missing function name falls back to metadata or returns error if no fallback."""
    response = api_client['submit'](
        code=correct_solution,
        function_name='',
        token=valid_token
    )
    
    # The API now falls back to metadata, so it might succeed
    # If there's no fallback, it should return 400
    assert response.status_code in [200, 400, 500]
    
    if response.status_code == 200:
        # If it succeeded, it means it fell back to metadata
        data = response.json()
        # Should still be able to run tests
        assert 'total' in data


def test_invalid_token_rejected(api_client, correct_solution):
    """Test that invalid tokens are rejected."""
    response = api_client['submit'](
        code=correct_solution,
        function_name='two_sum',
        token='invalid_token_12345'
    )
    
    assert response.status_code == 401


def test_empty_code_rejected(api_client, valid_token):
    """Test that empty code is rejected."""
    response = api_client['submit'](
        code='',
        function_name='two_sum',
        token=valid_token
    )
    
    assert response.status_code == 400
    data = response.json()
    assert 'error' in data


def test_syntax_error_detected(api_client, valid_token):
    """Test that syntax errors are detected and reported."""
    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
    )
    
    assert response.status_code == 400
    data = response.json()
    assert data['success'] is False
    assert 'syntax_error' in data or 'Syntax error' in data.get('error', '')


def test_runtime_error_handled(api_client, valid_token):
    """Test that runtime errors are handled gracefully."""
    error_code = '''def two_sum(nums, target):
    raise ValueError("Intentional error for testing")
'''
    
    response = api_client['submit'](
        code=error_code,
        function_name='two_sum',
        token=valid_token
    )
    
    assert response.status_code == 200
    data = response.json()
    
    # Should have test results with errors
    assert data['success'] is False
    assert data['passed'] == 0
    assert len(data['test_results']) > 0
    
    # First test should have an error
    first_test = data['test_results'][0]
    if not first_test.get('is_hidden', False):
        assert 'error' in first_test or not first_test.get('passed', False)


def test_custom_function_name_works(api_client, valid_token):
    """Test that custom function names (different from 'two_sum') work."""
    code = '''def my_custom_solution(nums, target):
    seen = {}
    for i, num in enumerate(nums):
        complement = target - num
        if complement in seen:
            return [seen[complement], i]
        seen[num] = i
    return []
'''
    
    response = api_client['submit'](
        code=code,
        function_name='my_custom_solution',
        token=valid_token
    )
    
    assert response.status_code == 200
    data = response.json()
    
    assert data['success'] is True
    assert data['passed'] == 7


def test_submission_with_helper_functions(api_client, valid_token):
    """Test that solutions with helper functions work correctly."""
    code = '''def helper(arr, val):
    """Helper to find value in array."""
    try:
        return arr.index(val)
    except ValueError:
        return -1

def two_sum(nums, target):
    """Main solution using helper."""
    seen = {}
    for i, num in enumerate(nums):
        complement = target - num
        if complement in seen:
            return [seen[complement], i]
        seen[num] = i
    return []
'''
    
    response = api_client['submit'](
        code=code,
        function_name='two_sum',
        token=valid_token
    )
    
    assert response.status_code == 200
    data = response.json()
    
    assert data['success'] is True


def test_test_results_include_all_required_fields(api_client, valid_token, correct_solution):
    """Test that test results include all required fields."""
    response = api_client['submit'](
        code=correct_solution,
        function_name='two_sum',
        token=valid_token
    )
    
    assert response.status_code == 200
    data = response.json()
    
    # Check response structure
    assert 'passed' in data
    assert 'failed' in data
    assert 'total' in data
    assert 'success' in data
    assert 'test_results' in data
    
    # Check each test result has required fields
    for test_result in data['test_results']:
        assert 'test_number' in test_result
        assert 'passed' in test_result
        assert 'description' in test_result
        
        # Public tests should have more details
        if not test_result.get('is_hidden', False):
            if not test_result['passed']:
                assert 'expected' in test_result or 'error' in test_result
                assert 'actual' in test_result or 'error' in test_result
