"""
Tests for HTTP API example scripts.

Validates that the example scripts under examples/api_usage/http/ exist,
are syntactically valid Python, and define the expected entry points.

The actual API functionality exercised by these examples is already covered
by test_rest_api.py and test_endpoints_health.py via the Flask test client.
"""

import ast
from pathlib import Path

import pytest

# Root of the repository
REPO_ROOT = Path(__file__).parent.parent.parent
EXAMPLES_DIR = REPO_ROOT / "examples" / "api_usage" / "http"

# All example scripts that should be tested — single source of truth
EXAMPLE_SCRIPTS = [
    "simple_working_example.py",
    "advanced/http_api_examples.py",
    "advanced/simple_http_example.py",
]


def _parse_example(relative_path: str) -> tuple[Path, str, ast.Module]:
    """Read and parse an example file, failing if it doesn't exist.

    Returns (path, source_text, ast_tree).
    """
    path = EXAMPLES_DIR / relative_path
    if not path.is_file():
        pytest.fail(f"Example not found: {path}")

    source = path.read_text(encoding="utf-8")
    tree = ast.parse(source, filename=str(path))
    return path, source, tree


def _has_main_guard(tree: ast.Module) -> bool:
    """Check if an AST contains an ``if __name__ == '__main__':`` guard."""
    for node in ast.walk(tree):
        if not isinstance(node, ast.If):
            continue
        test = node.test
        if not isinstance(test, ast.Compare):
            continue
        if len(test.ops) != 1 or not isinstance(test.ops[0], ast.Eq):
            continue
        # Match both orderings:
        #   __name__ == "__main__"
        #   "__main__" == __name__
        left = test.left
        comparators = test.comparators
        if len(comparators) != 1:
            continue
        right = comparators[0]
        if (
            isinstance(left, ast.Name)
            and left.id == "__name__"
            and isinstance(right, ast.Constant)
            and right.value == "__main__"
        ) or (
            isinstance(right, ast.Name)
            and right.id == "__name__"
            and isinstance(left, ast.Constant)
            and left.value == "__main__"
        ):
            return True
    return False


class TestHttpExamplesExist:
    """Verify that expected HTTP example files are present."""

    def test_examples_directory_exists(self):
        assert EXAMPLES_DIR.is_dir(), (
            f"Examples directory not found: {EXAMPLES_DIR}"
        )

    @pytest.mark.parametrize("relative_path", EXAMPLE_SCRIPTS)
    def test_example_file_exists(self, relative_path):
        path = EXAMPLES_DIR / relative_path
        assert path.is_file(), f"Missing example: {path}"


class TestHttpExamplesSyntax:
    """Verify that example scripts are syntactically valid Python."""

    @pytest.mark.parametrize("relative_path", EXAMPLE_SCRIPTS)
    def test_example_parses(self, relative_path):
        """Each example file must be valid Python (no syntax errors)."""
        _path, _source, tree = _parse_example(relative_path)
        assert tree is not None

    @pytest.mark.parametrize("relative_path", EXAMPLE_SCRIPTS)
    def test_example_has_main_function(self, relative_path):
        """Each example script should define a main() function."""
        _path, _source, tree = _parse_example(relative_path)

        function_names = [
            node.name
            for node in ast.walk(tree)
            if isinstance(node, ast.FunctionDef)
        ]
        assert "main" in function_names, (
            f"{relative_path} should define a main() function"
        )

    @pytest.mark.parametrize("relative_path", EXAMPLE_SCRIPTS)
    def test_example_has_main_guard(self, relative_path):
        """Each example script should have an if __name__ == '__main__' guard."""
        _path, _source, tree = _parse_example(relative_path)

        assert _has_main_guard(tree), (
            f"{relative_path} should have an if __name__ == '__main__' guard"
        )


class TestAdvancedExampleStructure:
    """Verify the advanced example defines expected helper classes/functions."""

    def test_ldr_client_class_defined(self):
        """The advanced example should define an LDRClient class."""
        _path, _source, tree = _parse_example("advanced/http_api_examples.py")

        class_names = [
            node.name
            for node in ast.walk(tree)
            if isinstance(node, ast.ClassDef)
        ]
        assert "LDRClient" in class_names, (
            "Advanced example should define LDRClient class"
        )

    def test_example_functions_defined(self):
        """The advanced example should define the documented example functions."""
        _path, _source, tree = _parse_example("advanced/http_api_examples.py")

        function_names = {
            node.name
            for node in ast.walk(tree)
            if isinstance(node, ast.FunctionDef)
        }

        expected_examples = [
            "example_quick_research",
            "example_settings_management",
            "example_research_history",
        ]
        for fn in expected_examples:
            assert fn in function_names, (
                f"Advanced example should define {fn}()"
            )
