"""Tests para parse_code_ast."""

import pytest

try:
    import tree_sitter  # noqa: F401
    HAS_TREE_SITTER = True
except ImportError:
    HAS_TREE_SITTER = False

from parse_code_ast import parse_code_ast, SUPPORTED_LANGUAGES

# ---------------------------------------------------------------------------
# Tests que no requieren tree-sitter
# ---------------------------------------------------------------------------

def test_lenguaje_no_soportado_lanza_value_error():
    """Lenguaje no soportado lanza ValueError con mensaje claro."""
    with pytest.raises(ValueError, match="no soportado"):
        parse_code_ast("x = 1", "cobol")


def test_lenguaje_no_soportado_lanza_value_error_vacio():
    """Lenguaje vacio lanza ValueError."""
    with pytest.raises(ValueError):
        parse_code_ast("x = 1", "")


def test_codigo_vacio_retorna_lista_vacia():
    """Codigo vacio retorna lista vacia sin invocar tree-sitter."""
    result = parse_code_ast("", "python")
    assert result == []


def test_codigo_solo_espacios_retorna_lista_vacia():
    """Codigo con solo espacios/newlines retorna lista vacia."""
    result = parse_code_ast("   \n\n\t  \n", "python")
    assert result == []


def test_alias_py_funciona():
    """Alias 'py' es aceptado como 'python'."""
    # Solo verificamos que no lanza ValueError por alias
    # Si tree-sitter no esta instalado, lanza ImportError (no ValueError)
    try:
        parse_code_ast("def f(): pass", "py")
    except ImportError:
        pass  # esperado si tree-sitter no instalado
    except ValueError:
        pytest.fail("'py' deberia ser alias valido de 'python'")


def test_alias_ts_funciona():
    """Alias 'ts' es aceptado como 'typescript'."""
    try:
        parse_code_ast("const x = 1;", "ts")
    except ImportError:
        pass
    except ValueError:
        pytest.fail("'ts' deberia ser alias valido de 'typescript'")


def test_lenguajes_soportados_incluyen_go_y_python():
    """SUPPORTED_LANGUAGES contiene los lenguajes principales."""
    assert "python" in SUPPORTED_LANGUAGES
    assert "go" in SUPPORTED_LANGUAGES
    assert "typescript" in SUPPORTED_LANGUAGES
    assert "rust" in SUPPORTED_LANGUAGES


# ---------------------------------------------------------------------------
# Tests que requieren tree-sitter
# ---------------------------------------------------------------------------

pytestmark_ts = pytest.mark.skipif(
    not HAS_TREE_SITTER,
    reason="tree-sitter no instalado"
)


@pytest.mark.skipif(not HAS_TREE_SITTER, reason="tree-sitter no instalado")
def test_python_extrae_funcion_simple():
    """Codigo Python con funcion simple retorna una entidad function."""
    source = '''\
def greet(name: str) -> str:
    """Saluda al usuario."""
    return f"Hello, {name}!"
'''
    try:
        import tree_sitter_python  # noqa: F401
    except ImportError:
        pytest.skip("tree-sitter-python no instalado")

    result = parse_code_ast(source, "python")
    assert len(result) == 1
    entity = result[0]
    assert entity.kind == "function"
    assert entity.name == "greet"
    assert entity.start_line == 1
    assert entity.language == "python"
    assert "greet" in entity.signature


@pytest.mark.skipif(not HAS_TREE_SITTER, reason="tree-sitter no instalado")
def test_python_extrae_clase_con_metodos():
    """Codigo Python con clase extrae clase y sus metodos como children."""
    source = '''\
class Animal:
    """Clase base de animales."""

    def __init__(self, name: str) -> None:
        self.name = name

    def speak(self) -> str:
        return ""
'''
    try:
        import tree_sitter_python  # noqa: F401
    except ImportError:
        pytest.skip("tree-sitter-python no instalado")

    result = parse_code_ast(source, "python")
    classes = [e for e in result if e.kind == "class"]
    assert len(classes) == 1
    cls = classes[0]
    assert cls.name == "Animal"
    assert len(cls.children) >= 1
    method_names = [c.name for c in cls.children]
    assert "speak" in method_names or "__init__" in method_names


@pytest.mark.skipif(not HAS_TREE_SITTER, reason="tree-sitter no instalado")
def test_python_extrae_docstring():
    """La entidad Python con docstring lo captura correctamente."""
    source = '''\
def documented():
    """Esta es la documentacion."""
    pass
'''
    try:
        import tree_sitter_python  # noqa: F401
    except ImportError:
        pytest.skip("tree-sitter-python no instalado")

    result = parse_code_ast(source, "python")
    assert len(result) == 1
    assert result[0].docstring is not None
    assert "documentacion" in result[0].docstring


@pytest.mark.skipif(not HAS_TREE_SITTER, reason="tree-sitter no instalado")
def test_go_extrae_funciones_y_tipos():
    """Codigo Go extrae funciones y tipos."""
    source = '''\
package main

// Add suma dos enteros.
func Add(a, b int) int {
    return a + b
}

type Point struct {
    X float64
    Y float64
}
'''
    try:
        import tree_sitter_go  # noqa: F401
    except ImportError:
        pytest.skip("tree-sitter-go no instalado")

    result = parse_code_ast(source, "go")
    names = [e.name for e in result]
    assert "Add" in names
    assert "Point" in names


@pytest.mark.skipif(not HAS_TREE_SITTER, reason="tree-sitter no instalado")
def test_typescript_extrae_interfaces():
    """Codigo TypeScript extrae interfaces y funciones."""
    source = '''\
interface User {
    id: number;
    name: string;
}

function greetUser(user: User): string {
    return `Hello, ${user.name}`;
}
'''
    try:
        import tree_sitter_typescript  # noqa: F401
    except ImportError:
        pytest.skip("tree-sitter-typescript no instalado")

    result = parse_code_ast(source, "typescript")
    kinds = [e.kind for e in result]
    assert "interface" in kinds or "function" in kinds


@pytest.mark.skipif(not HAS_TREE_SITTER, reason="tree-sitter no instalado")
def test_codigo_con_errores_de_sintaxis_es_tolerante():
    """tree-sitter es tolerante con errores de sintaxis: retorna lo que puede."""
    source = '''\
def valid_function():
    pass

def broken_function(
    # error: parentesis no cerrado
'''
    try:
        import tree_sitter_python  # noqa: F401
    except ImportError:
        pytest.skip("tree-sitter-python no instalado")

    # No debe lanzar excepcion — tree-sitter es tolerante a errores
    result = parse_code_ast(source, "python")
    # Al menos la funcion valida deberia extraerse
    names = [e.name for e in result]
    assert "valid_function" in names
