from src.file_cache import ASTParser

def test_ast_parser_initialization() -> None:
 """Verify that ASTParser can be initialized with a language string."""
 parser = ASTParser(language="python")
 assert parser.language.name == "python"

def test_ast_parser_parse() -> None:
 """Verify that the parse method returns a tree_sitter.Tree."""
 parser = ASTParser(language="python")
 code = "def hello(): print('world')"
 tree = parser.parse(code)
 assert tree is not None
 assert tree.root_node.type == "module"

def test_ast_parser_get_skeleton_python() -> None:
 """Verify that get_skeleton replaces function bodies with '...' while preserving docstrings."""
 parser = ASTParser(language="python")
 code = '''
def complex_function(a, b):
 """This is a docstring."""
 x = a + b
 return x

class MyClass:
 def method(self):
  """Method docstring."""
  pass
'''
 skeleton = parser.get_skeleton(code)
 assert 'def complex_function(a, b):' in skeleton
 assert '"""This is a docstring."""' in skeleton
 assert '...' in skeleton
 assert 'x = a + b' not in skeleton
 assert 'class MyClass:' in skeleton
 assert 'def method(self):' in skeleton
 assert '"""Method docstring."""' in skeleton

def test_ast_parser_get_skeleton_c() -> None:
 """Verify that get_skeleton replaces function bodies with '...' for C while preserving structs."""
 parser = ASTParser(language="c")
 code = """
struct MyStruct {
 int x;
};

void my_func() {
 printf("hello\\n");
}
"""
 skeleton = parser.get_skeleton(code)
 assert 'struct MyStruct {' in skeleton
 assert 'int x;' in skeleton
 assert 'void my_func()' in skeleton
 assert '...' in skeleton
 assert 'printf("hello\\n");' not in skeleton

def test_ast_parser_get_skeleton_cpp() -> None:
 """Verify that get_skeleton replaces function and method bodies with '...' for C++."""
 parser = ASTParser(language="cpp")
 code = """
class MyClass {
public:
 void myMethod() {
  int x = 1;
 }
};

template <typename T>
void myTemplateFunc(T x) {
 x.doSomething();
}
"""
 skeleton = parser.get_skeleton(code)
 assert 'class MyClass {' in skeleton
 assert 'void myMethod() { ... }' in skeleton
 assert 'template <typename T>' in skeleton
 assert 'void myTemplateFunc(T x) { ... }' in skeleton
 assert 'int x = 1;' not in skeleton
 assert 'x.doSomething();' not in skeleton

def test_ast_parser_invalid_language() -> None:
 """Verify handling of unsupported or invalid languages."""
 # Currently ASTParser defaults to Python if language not supported or just fails tree-sitter init
 # If it's intended to raise or handle gracefully, test it here.
 pass

def test_ast_parser_cpp_init() -> None:
 """Verify that ASTParser can be initialized with 'cpp'."""
 parser = ASTParser(language="cpp")
 assert parser.language_name == "cpp"

def test_ast_parser_c_init() -> None:
 """Verify that ASTParser can be initialized with 'c'."""
 parser = ASTParser(language="c")
 assert parser.language_name == "c"

def test_ast_parser_get_curated_view() -> None:
 """Verify that get_curated_view preserves function bodies with @core_logic or # [HOT]."""
 parser = ASTParser(language="python")
 code = '''
def normal_func():
 print("hide me")

@core_logic
def important_func():
 print("keep me")

def hot_func():
 # [HOT]
 print("keep me too")
'''
 curated = parser.get_curated_view(code)
 assert 'print("hide me")' not in curated
 assert 'print("keep me")' in curated
 assert 'print("keep me too")' in curated
 assert '@core_logic' in curated
 assert '# [HOT]' in curated

def test_ast_parser_get_targeted_view() -> None:
 """Verify get_targeted_view includes targeted functions and dependencies."""
 parser = ASTParser(language="python")
 code = '''
import sys

def dep2():
 """Dep 2"""
 print("dep2")

def dep1():
 """Dep 1"""
 dep2()

def targeted():
 """Targeted"""
 dep1()

def unrelated():
 """Unrelated"""
 print("unrelated")

class MyClass:
 def method1(self):
  """Method 1"""
  targeted()
 def method2(self):
  """Method 2"""
  pass
'''
 # Depth 0: targeted
 # Depth 1: dep1 (called by targeted)
 # Depth 2: dep2 (called by dep1)
 view = parser.get_targeted_view(code, ["targeted"])
 assert 'def targeted():' in view
 assert '"""Targeted"""' in view
 assert 'def dep1():' in view
 assert '"""Dep 1"""' in view
 assert 'def dep2():' in view
 assert '"""Dep 2"""' in view
 assert 'def unrelated():' not in view
 assert 'class MyClass:' not in view
 assert 'import sys' in view

 # Test depth limit
 # Depth 0: MyClass.method1
 # Depth 1: targeted (called by method1)
 # Depth 2: dep1 (called by targeted)
 # Depth 3: dep2 (called by dep1) -> should be elided
 view2 = parser.get_targeted_view(code, ["MyClass.method1"])
 assert 'class MyClass:' in view2
 assert 'def method1(self):' in view2
 assert 'def targeted():' in view2
 assert 'def dep1():' in view2
 assert 'def dep2():' not in view2
 assert 'def method2(self):' not in view2

def test_ast_parser_get_code_outline_c() -> None:
 """Verify that get_code_outline works for C."""
 parser = ASTParser(language="c")
 code = """
struct MyStruct {
 int x;
};

void my_func() {
 printf("hello\\n");
}
"""
 outline = parser.get_code_outline(code)
 assert '[Struct] MyStruct (Lines 2-4)' in outline
 assert '[Func] my_func (Lines 6-8)' in outline

def test_ast_parser_get_code_outline_cpp() -> None:
 """Verify that get_code_outline works for C++."""
 parser = ASTParser(language="cpp")
 code = """
class MyClass {
public:
 void myMethod() {
 }
};
"""
 outline = parser.get_code_outline(code)
 assert '[Class] MyClass (Lines 2-6)' in outline
 assert '  [Method] myMethod (Lines 4-5)' in outline

def test_ast_parser_get_definition_c() -> None:
 """Verify get_definition for C."""
 parser = ASTParser(language="c")
 code = """
void my_func() {
 printf("hello\\n");
}

struct MyStruct {
 int x;
};
"""
 def1 = parser.get_definition(code, "my_func")
 assert 'void my_func() {' in def1
 assert 'printf("hello\\n");' in def1
 
 def2 = parser.get_definition(code, "MyStruct")
 assert 'struct MyStruct {' in def2
 assert 'int x;' in def2

def test_ast_parser_get_definition_cpp() -> None:
 """Verify get_definition for C++ including scoped methods."""
 parser = ASTParser(language="cpp")
 code = """
class MyClass {
public:
 void myMethod() {
  int x = 1;
 }
};

namespace MyNamespace {
 void nsFunc() {}
}
"""
 # Scoped lookup
 def1 = parser.get_definition(code, "MyClass::myMethod")
 assert 'void myMethod() {' in def1
 assert 'int x = 1;' in def1

 # Just name lookup
 def2 = parser.get_definition(code, "myMethod")
 assert 'void myMethod() {' in def2

 # Namespace lookup
 def3 = parser.get_definition(code, "MyNamespace::nsFunc")
 assert 'void nsFunc() {}' in def3

def test_ast_parser_get_definition_cpp_template() -> None:
 """Verify get_definition for C++ templates."""
 parser = ASTParser(language="cpp")
 code = """
template <typename T>
void myTemplateFunc(T x) {
}
"""
 def1 = parser.get_definition(code, "myTemplateFunc")
 assert 'template <typename T>' in def1
 assert 'void myTemplateFunc(T x) {' in def1

def test_ast_parser_get_signature_c() -> None:
 """Verify get_signature for C."""
 parser = ASTParser(language="c")
 code = """
void my_func(int a,
             char* b) {
 printf("hello\\n");
}
"""
 sig = parser.get_signature(code, "my_func")
 assert 'void my_func(int a,' in sig
 assert 'char* b)' in sig
 assert '{' not in sig
 assert 'printf' not in sig

def test_ast_parser_get_signature_cpp() -> None:
 """Verify get_signature for C++ templates and methods."""
 parser = ASTParser(language="cpp")
 code = """
class MyClass {
public:
 template <typename T>
 T myTemplateMethod(T x) {
  return x;
 }
 
 void normalMethod() {
 }
};
"""
 # Template method
 sig1 = parser.get_signature(code, "MyClass::myTemplateMethod")
 assert 'template <typename T>' in sig1
 assert 'T myTemplateMethod(T x)' in sig1
 assert '{' not in sig1
 
 # Normal method
 sig2 = parser.get_signature(code, "MyClass::normalMethod")
 assert 'void normalMethod()' in sig2
 assert '{' not in sig2

def test_ast_parser_update_definition_cpp() -> None:
 """Verify update_definition for C++ including scoped methods."""
 parser = ASTParser(language="cpp")
 code = """
class MyClass {
public:
 void myMethod() {
  int x = 1;
 }
};
"""
 new_method = """ void myMethod() {
  int y = 2;
 }"""
 updated = parser.update_definition(code, "MyClass::myMethod", new_method)
 assert 'void myMethod() {' in updated
 assert 'int y = 2;' in updated
 assert 'int x = 1;' not in updated
 assert 'class MyClass {' in updated