"""Tests for JavaScript/TypeScript test generation."""

from core.languages.js_ts.testgen import _generate_import_statement, _is_valid_js_identifier, build_javascript_prompt


class TestIsValidJsIdentifier:
    """Tests for the _is_valid_js_identifier function."""

    def test_valid_identifier(self) -> None:
        """Test that valid identifiers return True."""
        assert _is_valid_js_identifier("MyClass") is True
        assert _is_valid_js_identifier("validName") is True
        assert _is_valid_js_identifier("_private") is True
        assert _is_valid_js_identifier("name123") is True

    def test_dollar_sign_identifiers(self) -> None:
        """Test that $ identifiers (valid in JavaScript) return True."""
        assert _is_valid_js_identifier("$handler") is True
        assert _is_valid_js_identifier("$") is True
        assert _is_valid_js_identifier("$scope") is True
        assert _is_valid_js_identifier("jQuery$") is True
        assert _is_valid_js_identifier("$_private") is True
        assert _is_valid_js_identifier("$$double") is True

    def test_reserved_words(self) -> None:
        """Test that reserved words return False."""
        assert _is_valid_js_identifier("module") is False
        assert _is_valid_js_identifier("exports") is False
        assert _is_valid_js_identifier("prototype") is False
        assert _is_valid_js_identifier("constructor") is False
        assert _is_valid_js_identifier("class") is False
        assert _is_valid_js_identifier("function") is False

    def test_invalid_identifiers(self) -> None:
        """Test that invalid identifiers return False."""
        assert _is_valid_js_identifier("123invalid") is False
        assert _is_valid_js_identifier("has-dash") is False
        assert _is_valid_js_identifier("has space") is False


class TestGenerateImportStatement:
    """Tests for the _generate_import_statement function."""

    def test_simple_function_import(self) -> None:
        """Test import generation for a simple function."""
        import_stmt, accessor = _generate_import_statement("execMongoEval", "../ctl/mongo_shell_utils")
        assert import_stmt == "const { execMongoEval } = require('../ctl/mongo_shell_utils');"
        assert accessor == "execMongoEval"

    def test_class_method_import(self) -> None:
        """Test import generation for a class method."""
        import_stmt, accessor = _generate_import_statement("Validator.validateRequest", "../middlewares/Validator")
        assert import_stmt == "const Validator = require('../middlewares/Validator');"
        assert accessor == "Validator.validateRequest"

    def test_nested_class_method_import(self) -> None:
        """Test import generation for a deeply nested method - falls back to module import."""
        import_stmt, accessor = _generate_import_statement("Constructor.prototype.method", "../utils/Constructor")
        # Multiple dots should fall back to module import
        assert "Constructor" in import_stmt
        assert accessor == "Constructor.prototype.method"

    def test_function_with_underscore(self) -> None:
        """Test import generation for a function with underscores."""
        import_stmt, accessor = _generate_import_statement("get_git_root", "../utils/git")
        assert import_stmt == "const { get_git_root } = require('../utils/git');"
        assert accessor == "get_git_root"

    def test_static_method_import(self) -> None:
        """Test import generation for what looks like a static method."""
        import_stmt, accessor = _generate_import_statement("Utils.formatDate", "../utils/Utils")
        assert import_stmt == "const Utils = require('../utils/Utils');"
        assert accessor == "Utils.formatDate"

    def test_reserved_word_class_name_falls_back(self) -> None:
        """Test that reserved words like 'module' fall back to module import."""
        import_stmt, accessor = _generate_import_statement("module.exports", "../utils")
        # 'module' is a reserved word, should fall back
        assert "module" not in import_stmt.split("=")[0]  # Not used as variable name
        assert accessor == "module.exports"

    def test_prototype_pattern_falls_back(self) -> None:
        """Test that prototype patterns fall back correctly."""
        import_stmt, accessor = _generate_import_statement("Array.prototype.map", "../polyfills")
        # 'prototype' in method name should still work for single dot
        # but Array.prototype.map has multiple dots, so falls back
        assert "polyfills" in import_stmt
        assert accessor == "Array.prototype.map"

    def test_exports_reserved_word(self) -> None:
        """Test that 'exports' as class name falls back."""
        import_stmt, accessor = _generate_import_statement("exports.helper", "../utils")
        # 'exports' is reserved, should fall back
        assert "const exports" not in import_stmt
        assert accessor == "exports.helper"


class TestBuildJavascriptPrompt:
    """Tests for the build_javascript_prompt function."""

    def test_simple_function_prompt_has_valid_import(self) -> None:
        """Test that prompts for simple functions have valid JS import syntax."""
        messages, _ = build_javascript_prompt(
            function_name="execMongoEval",
            function_code="async function execMongoEval() { return true; }",
            module_path="../ctl/utils",
            test_framework="jest",
            is_async=True,
        )
        user_content = messages[1]["content"]
        assert isinstance(user_content, str)
        # Should contain valid destructuring import
        assert "const { execMongoEval }" in user_content
        # Should NOT contain invalid syntax with dots in destructuring
        assert "const { execMongoEval." not in user_content

    def test_class_method_prompt_has_valid_import(self) -> None:
        """Test that prompts for class methods have valid JS import syntax."""
        messages, _ = build_javascript_prompt(
            function_name="Validator.validateRequest",
            function_code="class Validator { validateRequest() {} }",
            module_path="../middlewares/Validator",
            test_framework="jest",
            is_async=False,
        )
        user_content = messages[1]["content"]
        assert isinstance(user_content, str)
        # Should contain valid class import
        assert "const Validator = require('../middlewares/Validator');" in user_content
        # Should NOT contain invalid syntax like { Validator.validateRequest }
        assert "{ Validator.validateRequest }" not in user_content

    def test_async_prompt_has_valid_import(self) -> None:
        """Test that async prompts also have valid import syntax."""
        messages, suffix = build_javascript_prompt(
            function_name="Controller.asyncMethod",
            function_code="class Controller { async asyncMethod() {} }",
            module_path="../controllers/Controller",
            test_framework="jest",
            is_async=True,
        )
        assert suffix == "async-"
        user_content = messages[1]["content"]
        assert isinstance(user_content, str)
        # Should contain valid class import
        assert "const Controller = require('../controllers/Controller');" in user_content

    def test_prompt_contains_function_accessor(self) -> None:
        """Test that the prompt contains the correct function accessor."""
        messages, _ = build_javascript_prompt(
            function_name="MyClass.myMethod",
            function_code="class MyClass { myMethod() {} }",
            module_path="../MyClass",
            test_framework="jest",
            is_async=False,
        )
        user_content = messages[1]["content"]
        assert isinstance(user_content, str)
        # The function accessor should be used in describe blocks
        assert "describe('MyClass.myMethod'" in user_content
