from __future__ import annotations

import pytest

from testgen.postprocessing.code_validator import validate_testgen_code


def test_valid_code() -> None:
    code: str = """def test_function():
    x = 1
    y = 2
    return x + y"""

    result: str = validate_testgen_code(code, python_version=(3, 11, 0))
    assert result == code


def test_empty_code() -> None:
    with pytest.raises(ValueError, match="No code was generated when generating tests"):
        validate_testgen_code("", python_version=(3, 11, 0))


def test_whitespace_only() -> None:
    with pytest.raises(ValueError, match="No code was generated when generating tests"):
        validate_testgen_code("   \n   \n", python_version=(3, 11, 0))


def test_incomplete_function_definition() -> None:
    code: str = """def test_function():
    x = 1
    y = """

    expected: str = """def test_function():
    x = 1"""

    result: str = validate_testgen_code(code, python_version=(3, 11, 0))
    assert result == expected


def test_truncation_limit() -> None:
    code: str = """def test_function():
        x = 
        y = 2
        z = 3
        return x + y"""

    max_lines: int = 2
    with pytest.raises(
        ValueError, match=f"Invalid test code generated, failed to validate code even after removing {max_lines} lines"
    ):
        validate_testgen_code(code, python_version=(3, 11, 0), max_lines_to_remove=max_lines)


def test_incomplete_statement_at_end() -> None:
    code: str = """def test_function():
    x = 1
    print("""

    expected: str = """def test_function():
    x = 1"""

    result: str = validate_testgen_code(code, python_version=(3, 11, 0))
    assert result == expected


def test_syntax_error_in_middle() -> None:
    code: str = """def test_function():
    x = %
    y = 2
    return x + y"""

    with pytest.raises(ValueError, match="Invalid test code generated"):
        validate_testgen_code(code, python_version=(3, 11, 0))


def test_multiple_functions_with_error() -> None:
    code: str = """def test_function1():
    return 1

def test_function2():
    x = 1
    return x

def test_function3():
    y = """

    expected: str = """def test_function1():
    return 1

def test_function2():
    x = 1
    return x"""

    result: str = validate_testgen_code(code, python_version=(3, 11, 0))
    assert result == expected


def test_just_def() -> None:
    code: str = "def test_"
    with pytest.raises(ValueError, match="Invalid test code generated"):
        validate_testgen_code(code, python_version=(3, 11, 0))


def test_broken_def() -> None:
    code: str = """def test_function1():
    return 1

def test_function2():
    x = 1
    return x

def"""

    expected: str = """def test_function1():
    return 1

def test_function2():
    x = 1
    return x"""
    result: str = validate_testgen_code(code, python_version=(3, 11, 0))
    assert result == expected


def test_pytest_style() -> None:
    code: str = """def test_something():
        pass"""
    result: str = validate_testgen_code(code, python_version=(3, 11, 0))
    assert result == code


def test_unittest_style() -> None:
    code: str = """class TestCase(unittest.TestCase):
        def test_something(self):
            pass"""
    result: str = validate_testgen_code(code, python_version=(3, 11, 0))
    assert result == code


def test_no_test_function() -> None:
    code: str = """def something():
        pass"""
    with pytest.raises(ValueError, match="No test functions were found in the generated code"):
        validate_testgen_code(code, python_version=(3, 11, 0))


def test_unittest_without_test_prefix() -> None:
    code: str = """class TestCase(unittest.TestCase):
        def something(self):
            pass"""
    with pytest.raises(ValueError, match="No test functions were found in the generated code"):
        validate_testgen_code(code, python_version=(3, 11, 0))


def test_remove_lines_with_test() -> None:
    code: str = """def test_one():
        pass

class MyTests(TestCase):
    def tes"""
    expected: str = """def test_one():
        pass"""
    result: str = validate_testgen_code(code, python_version=(3, 11, 0))
    assert result == expected


def test_existing_future_annotations() -> None:
    code: str = """from __future__ import annotations


def test_function():
    x: list[int] = [1, 2, 3]
    return x[0]"""

    expected: str = """from __future__ import annotations


def test_function():
    x: list[int] = [1, 2, 3]
    return x[0]"""

    result: str = validate_testgen_code(code, python_version=(3, 11, 0))
    assert result == expected


def test_comments_before_future_import() -> None:
    code: str = """# This is a test file
import pytest as test

from __future__ import annotations

# With multiple comments
def test_function():
    x: list[int] = [1, 2, 3]
    return x[0]"""

    expected: str = """from __future__ import annotations

# This is a test file
import pytest as test


# With multiple comments
def test_function():
    x: list[int] = [1, 2, 3]
    return x[0]"""

    result: str = validate_testgen_code(code, python_version=(3, 11, 0))
    assert result == expected


def test_multiple_future_imports() -> None:
    code: str = """from __future__ import division
from pytest import test
from __future__ import print_function

def test_function():
    x: list[int] = [1, 2, 3]
    return x[0]"""

    expected: str = """from __future__ import division, print_function

from pytest import test


def test_function():
    x: list[int] = [1, 2, 3]
    return x[0]"""

    result: str = validate_testgen_code(code, python_version=(3, 11, 0))
    assert result == expected
