import os

import pytest

from py_agent.infrastructure.coverage_runner import find_test_files

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _create_files(base_dir, relative_paths: list[str]) -> list[str]:
    """Create empty files under *base_dir* and return their absolute paths."""
    created = []
    for rel in relative_paths:
        full = base_dir / rel
        full.parent.mkdir(parents=True, exist_ok=True)
        full.touch()
        created.append(str(full))
    return created


# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------


def test_returns_list_type(tmp_path):
    """Return value is always a list, even for an empty directory."""
    result = find_test_files(str(tmp_path))
    assert isinstance(result, list)


def test_empty_directory_returns_empty_list(tmp_path):
    """No files in the directory → empty list."""
    result = find_test_files(str(tmp_path))
    assert result == []


def test_finds_test_prefix_files(tmp_path):
    """Files starting with 'test_' and ending with '.py' are collected."""
    _create_files(tmp_path, ["test_foo.py", "test_bar.py"])
    result = find_test_files(str(tmp_path))
    assert len(result) == 2
    basenames = {os.path.basename(p) for p in result}
    assert basenames == {"test_foo.py", "test_bar.py"}


def test_finds_test_suffix_files(tmp_path):
    """Files ending with '_test.py' are collected."""
    _create_files(tmp_path, ["foo_test.py", "bar_test.py"])
    result = find_test_files(str(tmp_path))
    basenames = {os.path.basename(p) for p in result}
    assert basenames == {"foo_test.py", "bar_test.py"}


def test_finds_both_prefix_and_suffix_files(tmp_path):
    """Both 'test_*.py' and '*_test.py' files are collected together."""
    _create_files(tmp_path, ["test_alpha.py", "beta_test.py"])
    result = find_test_files(str(tmp_path))
    basenames = {os.path.basename(p) for p in result}
    assert basenames == {"test_alpha.py", "beta_test.py"}


def test_excludes_non_test_python_files(tmp_path):
    """Python files that don't match either pattern are excluded."""
    _create_files(tmp_path, ["utils.py", "conftest.py", "mymodule.py"])
    result = find_test_files(str(tmp_path))
    assert result == []


def test_excludes_non_python_files_with_test_name(tmp_path):
    """Non-.py files with test-like names are excluded."""
    _create_files(tmp_path, ["test_something.txt", "test_other.sh", "test_data.csv"])
    result = find_test_files(str(tmp_path))
    assert result == []


def test_finds_files_in_subdirectories(tmp_path):
    """test files nested in subdirectories are discovered recursively."""
    _create_files(tmp_path, ["subdir/nested/test_deep.py", "subdir/top_test.py"])
    result = find_test_files(str(tmp_path))
    basenames = {os.path.basename(p) for p in result}
    assert basenames == {"test_deep.py", "top_test.py"}


def test_returned_paths_are_absolute_and_correct(tmp_path):
    """Returned paths point to the actual files (full path, not just basename)."""
    expected_rel = "sub/test_verify.py"
    _create_files(tmp_path, [expected_rel])
    result = find_test_files(str(tmp_path))
    assert len(result) == 1
    assert result[0] == str(tmp_path / expected_rel)


def test_mixed_test_and_non_test_files(tmp_path):
    """Only test files are returned when mixed with non-test files."""
    _create_files(
        tmp_path,
        ["test_good.py", "helper.py", "good_test.py", "README.md", "run.sh"],
    )
    result = find_test_files(str(tmp_path))
    basenames = {os.path.basename(p) for p in result}
    assert basenames == {"test_good.py", "good_test.py"}


@pytest.mark.parametrize(
    "filename",
    [
        "test_.py",  # minimal test_ prefix
        "_test.py",  # minimal _test suffix
    ],
)
def test_boundary_filenames_are_collected(tmp_path, filename):
    """Minimal valid test filenames satisfying the naming rules are collected."""
    _create_files(tmp_path, [filename])
    result = find_test_files(str(tmp_path))
    assert len(result) == 1
    assert os.path.basename(result[0]) == filename


def test_no_duplicates_in_result(tmp_path):
    """Each test file appears exactly once in the result."""
    names = ["test_a.py", "test_b.py", "c_test.py"]
    _create_files(tmp_path, names)
    result = find_test_files(str(tmp_path))
    assert len(result) == len(set(result))
