
import pytest
from semantica.utils.types import Entity
from semantica.kg.graph_builder import GraphBuilder
from semantica.kg.entity_resolver import EntityResolver
from semantica.kg.graph_analyzer import GraphAnalyzer

def test_full_entity_pipeline():
    """
    Tests the full pipeline using Entity objects:
    Builder -> Resolver -> Analyzer
    This specifically verifies the fix for 'unhashable type: Entity'
    and the robustness of ID extraction.
    """
    # 1. Create Entity objects
    e1 = Entity(id="ent1", text="Entity 1", type="PERSON")
    e2 = Entity(id="ent2", text="Entity 2", type="ORG")
    e3 = Entity(id="ent3", text="Entity 3", type="LOCATION")

    # 2. Define relationships using Entity objects
    relationships = [
        {"source": e1, "target": e2, "type": "WORKS_AT"},
        {"source": e2, "target": e3, "type": "LOCATED_IN"},
        {"source": e1, "target": e3, "type": "LIVES_IN"}
    ]

    # 3. Build the graph
    builder = GraphBuilder()
    # Provide both entities and relationships
    sources = {
        "entities": [e1, e2, e3],
        "relationships": relationships
    }
    graph_data = builder.build(sources=sources)
    
    # DEBUG: Print graph_data keys and entities count
    print(f"DEBUG: graph_data keys: {list(graph_data.keys())}")
    print(f"DEBUG: Entities count: {len(graph_data.get('entities', []))}")
    print(f"DEBUG: Relationships count: {len(graph_data.get('relationships', []))}")
    if graph_data.get('entities'):
        print(f"DEBUG: First entity: {graph_data['entities'][0]}")

    # Verify graph data contains the entities and normalized relationships
    assert len(graph_data["entities"]) >= 3
    assert len(graph_data["relationships"]) == 3
    
    # 4. Resolve entities
    resolver = EntityResolver()
    resolved_entities = resolver.resolve_entities(graph_data["entities"])
    resolved_graph = {
        "entities": resolved_entities,
        "relationships": graph_data["relationships"]
    }
    
    # 5. Analyze the graph
    # This is where the 'unhashable type: Entity' usually occurred
    analyzer = GraphAnalyzer()
    analysis_results = analyzer.analyze(resolved_graph)
    
    # Verify analysis results
    assert "centrality" in analysis_results
    assert "communities" in analysis_results
    assert "connectivity" in analysis_results
    
    # Verify specific metrics are present
    centrality = analysis_results["centrality"]
    assert "centrality_measures" in centrality
    # It seems by default it might only calculate degree
    assert "degree" in centrality["centrality_measures"]
    
    # Verify connectivity
    connectivity = analysis_results["connectivity"]
    assert "is_connected" in connectivity
    assert connectivity["is_connected"] is True
    assert connectivity["num_components"] == 1
    
    print("Full pipeline test passed successfully!")

def test_direct_entity_objects_in_analyzer():
    """
    Specifically tests the fix for 'unhashable type: Entity' when
    Entity objects are directly passed in the relationships to GraphAnalyzer.
    This simulates the scenario reported by users where the graph 
    contains Entity objects instead of IDs.
    """
    # 1. Create Entity objects
    e1 = Entity(id="ent1", text="Entity 1", type="PERSON")
    e2 = Entity(id="ent2", text="Entity 2", type="ORG")
    
    # 2. Define relationships directly using Entity objects
    # In some scenarios, the user might pass objects instead of strings
    graph = {
        "entities": [e1, e2],
        "relationships": [
            {"source": e1, "target": e2, "type": "CONNECTED_TO"}
        ]
    }
    
    # 3. Analyze the graph
    analyzer = GraphAnalyzer()
    
    # This should not raise TypeError: unhashable type: 'Entity'
    analysis_results = analyzer.analyze(graph)
    
    assert "centrality" in analysis_results
    assert "metrics" in analysis_results
    
    print("Direct Entity objects test passed successfully!")

if __name__ == "__main__":
    test_full_entity_pipeline()
    test_direct_entity_objects_in_analyzer()
