
import logging
from typing import List, Dict, Any, Optional
from vector_backends import VectorManager, VectorDocument

class SynapseLinker:
    """
    Automated Synapse Linking (Graph-RAG).
    
    Compliant with Patent #5 (Multi-Model Consensus) & Patent #3 (Risk Assessment).
    
    Responsibility:
    - Find semantically related memories.
    - Establish bidirectional links.
    - Evaluate risk of new nodes.
    """
    
    def __init__(self, vector_manager: VectorManager):
        self.vm = vector_manager
        self.logger = logging.getLogger("SynapseLinker")
        
    def link_memory(self, memory_id: str, content: str, 
                   domain: str = "general", 
                   threshold: float = 0.75) -> List[str]:
        """
        Link a new memory to its semantic neighbors.
        """
        if not self.vm.available:
            return []
            
        try:
            # 1. Search for neighbors
            neighbors = self.vm.search(content, top_k=3)
            links = []
            
            for doc in neighbors:
                if doc.id == memory_id:
                    continue
                
                print(f"      SYNAPSE DEBUG: Neighbor {doc.id} score: {doc.score:.3f}")
                
                # 2. Establish links if similarity is high
                if doc.score >= threshold:
                    links.append(doc.id)
                    print(f"🕸️ SYNAPSE: Established link {memory_id} <-> {doc.id} (score: {doc.score:.3f})")
            
            # 3. Assess Risk (Patent #3)
            risk_level = self._assess_risk(content, neighbors)
            
            return links, risk_level
            
        except Exception as e:
            self.logger.error(f"Synapse linking failed: {e}")
            return [], "low"

    def _assess_risk(self, content: str, neighbors: List[VectorDocument]) -> str:
        """
        Multi-dimensional risk assessment (Patent #3).
        Checks for semantic contradictions or unusual patterns.
        """
        # Simple heuristic for now: 
        # If neighbors exist but have very low similarity to a success-framed memory,
        # or if content contains 'warning', 'critical', 'fail' but neighbors are positive.
        
        lower_content = content.lower()
        risk_indicators = ["fail", "error", "critical", "warning", "violation", "unauthorized"]
        
        has_indicator = any(ind in lower_content for ind in risk_indicators)
        
        if has_indicator:
            return "medium"
            
        # Contradiction check: 
        # If content says one thing and the closest neighbor says the opposite (simple keyword check)
        for doc in neighbors:
            if doc.score > 0.9:
                if "true" in lower_content and "false" in doc.content.lower():
                    return "high"
                if "success" in lower_content and "fail" in doc.content.lower():
                    return "high"
        
        return "low"
