"""Tests for _test_discovery.replay — replay test detection."""

from __future__ import annotations

import textwrap
from pathlib import Path

from codeflash_python.test_discovery.replay import (
    discover_replay_test_files,
    is_replay_test,
    parse_replay_test_metadata,
)


class TestIsReplayTest:
    """is_replay_test path detection."""

    def test_replay_test_in_filename(self) -> None:
        """Returns True when __replay_test is in the filename."""
        path = Path("tests/__replay_test_module.py")
        assert is_replay_test(path) is True

    def test_replay_test_in_parent_directory(self) -> None:
        """Returns True when __replay_test is in a parent directory name."""
        path = Path("tests/__replay_test/test_something.py")
        assert is_replay_test(path) is True

    def test_regular_test_file(self) -> None:
        """Returns False for a regular test file."""
        path = Path("tests/test_something.py")
        assert is_replay_test(path) is False

    def test_replay_without_double_underscore(self) -> None:
        """Returns False when path has 'replay' but not '__replay_test'."""
        path = Path("tests/replay_test_module.py")
        assert is_replay_test(path) is False


class TestParseReplayTestMetadata:
    """parse_replay_test_metadata AST extraction."""

    def test_valid_replay_file(self, tmp_path: Path) -> None:
        """Returns ReplayTestMetadata with both fields extracted."""
        test_file = tmp_path / "test_replay.py"
        test_file.write_text(
            "import warnings\n"
            "import dill as pickle\n"
            "from codeflash.tracing.replay_test "
            "import get_next_arg_and_return\n"
            "\n"
            'functions = ["my_function", "other_function"]\n'
            'trace_file_path = r"/tmp/trace_abc123.db"\n'
            "\n"
            "def test_some_module_my_function():\n"
            "    for arg_val_pkl in get_next_arg_and_return():\n"
            "        pass\n",
        )
        result = parse_replay_test_metadata(test_file)
        assert result is not None
        trace = "/tmp/trace_abc123.db"
        assert Path(trace) == result.trace_file_path
        assert ("my_function", "other_function") == result.function_names

    def test_single_function(self, tmp_path: Path) -> None:
        """Handles a functions list with a single item."""
        test_file = tmp_path / "test_replay.py"
        test_file.write_text(
            textwrap.dedent("""\
                functions = ["only_one"]
                trace_file_path = r"/tmp/trace.db"
            """),
        )
        result = parse_replay_test_metadata(test_file)
        assert result is not None
        assert ("only_one",) == result.function_names

    def test_empty_functions_list(self, tmp_path: Path) -> None:
        """Returns metadata with empty tuple when functions list is empty."""
        test_file = tmp_path / "test_replay.py"
        test_file.write_text(
            textwrap.dedent("""\
                functions = []
                trace_file_path = r"/tmp/trace.db"
            """),
        )
        result = parse_replay_test_metadata(test_file)
        assert result is not None
        assert () == result.function_names

    def test_missing_functions(self, tmp_path: Path) -> None:
        """Returns None when functions assignment is missing."""
        test_file = tmp_path / "test_replay.py"
        test_file.write_text(
            textwrap.dedent("""\
                trace_file_path = r"/tmp/trace.db"
            """),
        )
        assert parse_replay_test_metadata(test_file) is None

    def test_missing_trace_file_path(self, tmp_path: Path) -> None:
        """Returns None when trace_file_path assignment is missing."""
        test_file = tmp_path / "test_replay.py"
        test_file.write_text(
            textwrap.dedent("""\
                functions = ["my_function"]
            """),
        )
        assert parse_replay_test_metadata(test_file) is None

    def test_empty_file(self, tmp_path: Path) -> None:
        """Returns None for an empty file."""
        test_file = tmp_path / "test_replay.py"
        test_file.write_text("")
        assert parse_replay_test_metadata(test_file) is None

    def test_syntax_error(self, tmp_path: Path) -> None:
        """Returns None for a file with a syntax error."""
        test_file = tmp_path / "test_replay.py"
        test_file.write_text("def broken(\n")
        assert parse_replay_test_metadata(test_file) is None

    def test_nonexistent_file(self, tmp_path: Path) -> None:
        """Returns None when the file does not exist."""
        test_file = tmp_path / "does_not_exist.py"
        assert parse_replay_test_metadata(test_file) is None


class TestDiscoverReplayTestFiles:
    """discover_replay_test_files directory scanning."""

    def test_mixed_replay_and_regular(self, tmp_path: Path) -> None:
        """Returns only files with __replay_test in their path."""
        replay_dir = tmp_path / "__replay_test"
        replay_dir.mkdir()
        (replay_dir / "test_replay_a.py").write_text("pass\n")
        (tmp_path / "test_regular.py").write_text("pass\n")

        result = discover_replay_test_files(tmp_path)

        assert 1 == len(result)
        assert "__replay_test" in str(result[0])

    def test_empty_directory(self, tmp_path: Path) -> None:
        """Returns empty list for a directory with no Python files."""
        assert [] == discover_replay_test_files(tmp_path)

    def test_nested_replay_subdirectory(self, tmp_path: Path) -> None:
        """Finds replay test files in nested __replay_test subdirectories."""
        nested = tmp_path / "sub" / "__replay_test"
        nested.mkdir(parents=True)
        (nested / "test_deep.py").write_text("pass\n")

        result = discover_replay_test_files(tmp_path)

        assert 1 == len(result)
        assert "test_deep.py" == result[0].name

    def test_sorted_results(self, tmp_path: Path) -> None:
        """Returns results in sorted order."""
        replay_dir = tmp_path / "__replay_test"
        replay_dir.mkdir()
        (replay_dir / "test_b.py").write_text("pass\n")
        (replay_dir / "test_a.py").write_text("pass\n")
        (replay_dir / "test_c.py").write_text("pass\n")

        result = discover_replay_test_files(tmp_path)

        assert result == sorted(result)
        assert 3 == len(result)
