"""Tests for call graph parser."""

from __future__ import annotations

from pathlib import Path

from vibelexity.call_graph.parsers.python import PythonCallParser
from vibelexity.parsers.python import parse


def test_extract_function_definitions():
    code = """
def foo(x, y):
    return x + y

class Bar:
    def method_a(self):
        pass
    
    def method_b(self):
        pass

def baz():
    pass
"""
    parser = PythonCallParser()
    root = parse(code)
    defs = parser.extract_function_definitions(root, code, "/tmp/test.py")

    assert len(defs) == 4
    def_names = [d.name for d in defs]
    assert "foo" in def_names
    assert "method_a" in def_names
    assert "method_b" in def_names
    assert "baz" in def_names

    func_def = next(d for d in defs if d.name == "foo")
    assert func_def.def_type == "function"
    assert len(func_def.params) == 2

    method_def = next(d for d in defs if d.name == "method_a")
    assert method_def.def_type == "method"
    assert method_def.class_name == "Bar"


def test_extract_simple_calls():
    code = """
def foo():
    bar()
    
def bar():
    baz()

def baz():
    pass
"""
    parser = PythonCallParser()
    root = parse(code)
    defs = parser.extract_function_definitions(root, code, "/tmp/test.py")
    calls = parser.extract_calls(root, code, "/tmp/test.py", defs)

    assert len(calls) == 2

    call_names = [c.callee_function for c in calls]
    assert "bar" in call_names
    assert "baz" in call_names

    foo_to_bar = next(c for c in calls if c.caller_function == "foo")
    assert foo_to_bar.callee_function == "bar"
    assert foo_to_bar.call_type == "local"


def test_extract_method_calls():
    code = """
class MyClass:
    def foo(self):
        self.bar()
        
    def bar(self):
        pass
"""
    parser = PythonCallParser()
    root = parse(code)
    defs = parser.extract_function_definitions(root, code, "/tmp/test.py")
    calls = parser.extract_calls(root, code, "/tmp/test.py", defs)

    assert len(calls) == 1
    assert calls[0].callee_function == "bar"
    assert calls[0].call_type == "method"
    assert calls[0].receiver_object == "self"


def test_extract_external_calls():
    code = """
def foo():
    print("hello")
    len([1, 2, 3])
"""
    parser = PythonCallParser()
    root = parse(code)
    defs = parser.extract_function_definitions(root, code, "/tmp/test.py")
    calls = parser.extract_calls(root, code, "/tmp/test.py", defs)

    assert len(calls) == 2
    external_calls = [c for c in calls if c.call_type == "external"]
    assert len(external_calls) == 2
