#!/usr/bin/env python3
"""
Bounded Hierarchical Context System Demo

This script demonstrates the complete intelligent context system:

1. **Bounded Hierarchy Walking**: Context resolution with configurable depth limits
2. **Global Context Support**: Contexts that apply everywhere regardless of hierarchy
3. **Decision-Hop Temporal Analysis**: Track related decisions by decision distance (not time)
4. **Space-Efficient Storage**: CSS-like cascading eliminates redundant metadata
5. **Smart Context Resolution**: Intelligent lookup with caching and inheritance

Key Innovations:
- Hierarchy traversal stops at configurable depth (user's "bounded" requirement)
- Global contexts provide system-wide applicable context
- Temporal analysis based on decision hops, not chronological time
- RAG-like decision finding: discover decisions x hops away conceptually

Usage:
    python3 bounded_context_demo.py [--max-depth N] [--demo-global] [--decision-hops N]
"""

import argparse
import json
import logging
from pathlib import Path
from datetime import datetime, timezone

from .cascading_metadata_generator import CascadingMetadataSystem
from .context_resolver import CascadingContextResolver
from ..temporal.temporal_context_system import (
    TemporalContextGraph, 
    ContextChangeReason, 
    DecisionMetadata
)

logging.basicConfig(level=logging.INFO, format='%(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class BoundedContextSystem:
    """Complete bounded hierarchical context system with temporal decision analysis"""
    
    def __init__(self, project_path: str, metadata_base: str, max_hierarchy_depth: int = 10):
        self.project_path = Path(project_path)
        self.metadata_base = Path(metadata_base)
        self.max_hierarchy_depth = max_hierarchy_depth
        
        # Initialize subsystems
        self.cascading_system = None
        self.context_resolver = None
        self.temporal_graph = None
        
        # Ensure metadata directory exists
        self.metadata_base.mkdir(parents=True, exist_ok=True)
    
    def initialize_system(self, project_name: str = "BZZZ") -> None:
        """Initialize all components of the bounded context system"""
        
        logger.info("🚀 Initializing Bounded Hierarchical Context System")
        logger.info(f"   📁 Project: {self.project_path}")
        logger.info(f"   💾 Metadata: {self.metadata_base}")
        logger.info(f"   📏 Max depth: {self.max_hierarchy_depth}")
        
        # 1. Initialize cascading metadata generator
        self.cascading_system = CascadingMetadataSystem(
            bzzz_path=str(self.project_path),
            rag_endpoint="http://localhost:8000/query",  # Not used in this demo
            metadata_base=str(self.metadata_base)
        )
        
        # 2. Initialize context resolver with bounded depth
        metadata_dir = self.metadata_base / project_name
        self.context_resolver = CascadingContextResolver(
            str(metadata_dir), 
            max_hierarchy_depth=self.max_hierarchy_depth
        )
        
        # 3. Initialize temporal graph for decision analysis
        self.temporal_graph = TemporalContextGraph(
            str(self.metadata_base), 
            project_name
        )
        
        logger.info("✅ All systems initialized")
    
    def generate_hierarchical_metadata(self) -> dict:
        """Generate the cascading hierarchical metadata system"""
        
        logger.info("\n🏗️ Generating Hierarchical Metadata System")
        logger.info("=" * 50)
        
        # Process repository with cascading system
        results = self.cascading_system.process_repository()
        
        logger.info(f"✅ Generated hierarchical metadata:")
        logger.info(f"   📊 Processed {results['paths_processed']} paths")
        logger.info(f"   🏗️ Created {results['context_nodes']} context nodes")
        logger.info(f"   💾 Space savings: {results['space_savings_percent']:.1f}%")
        logger.info(f"   📏 Traditional size: {results['estimated_traditional_size_kb']} KB")
        logger.info(f"   🎯 Actual size: {results['actual_size_kb']} KB")
        
        return results
    
    def setup_global_contexts(self) -> None:
        """Set up global contexts that apply to all paths"""
        
        logger.info("\n🌐 Setting Up Global Contexts")
        logger.info("=" * 30)
        
        # Global BZZZ project context
        global_bzzz_context = {
            'id': 'global_bzzz',
            'summary': 'BZZZ Distributed Contextual Metadata System',
            'purpose': 'Unified contextual exchange protocol with 1:1 filesystem mapping',
            'technologies': ['UCXL Protocol', 'Distributed Systems', 'Contextual Metadata'],
            'tags': ['bzzz', 'ucxl', 'distributed', 'metadata', 'global'],
            'insights': [
                'Part of CHORUS ecosystem for AI development',
                'Implements hierarchical context inheritance',
                'Supports temporal decision tracking',
                'Enables space-efficient metadata storage'
            ],
            'is_global': True,
            'context_specificity': -1
        }
        
        # Global development practices context
        global_dev_context = {
            'id': 'global_development',
            'summary': 'Development practices and architectural principles',
            'purpose': 'Ensure consistent development patterns across all components',
            'technologies': ['Git', 'Testing', 'Documentation', 'Code Review'],
            'tags': ['development', 'practices', 'architecture', 'global'],
            'insights': [
                'All components follow consistent architectural patterns',
                'Code changes tracked through decision-based temporal evolution',
                'Comprehensive testing and documentation required',
                'Context inheritance reduces maintenance overhead'
            ],
            'is_global': True,
            'context_specificity': -1
        }
        
        # Add global contexts
        self.context_resolver.add_global_context(global_bzzz_context)
        self.context_resolver.add_global_context(global_dev_context)
        
        logger.info(f"✅ Added {len(self.context_resolver.global_contexts)} global contexts")
        logger.info("   🌍 BZZZ Project Context (applies to all files)")
        logger.info("   🛠️ Development Practices Context (applies to all files)")
    
    def demonstrate_bounded_resolution(self) -> None:
        """Demonstrate bounded hierarchy walking with context resolution"""
        
        logger.info(f"\n📏 Bounded Context Resolution Demo (max depth: {self.max_hierarchy_depth})")
        logger.info("=" * 60)
        
        # Test addresses at different depths
        test_addresses = [
            "ucxl://any:any@BZZZ:RUSTLE-testing/src/main.rs",
            "ucxl://any:any@BZZZ:RUSTLE-testing/src/api/handlers.rs",
            "ucxl://any:any@BZZZ:RUSTLE-testing/tests/unit/core_tests.rs",
            "ucxl://any:any@BZZZ:RUSTLE-testing/assets/fonts/README.md"
        ]
        
        for address in test_addresses:
            logger.info(f"\n🔍 Resolving: {address}")
            
            context = self.context_resolver.resolve(address)
            if context:
                logger.info(f"   📝 Summary: {context.summary}")
                logger.info(f"   🏷️ Tags: {', '.join(context.tags[:5])}")
                logger.info(f"   📊 Inheritance chain: {len(context.inheritance_chain)} levels")
                logger.info(f"   🌐 Global contexts applied: {hasattr(context, 'global_contexts_applied')}")
                logger.info(f"   ⚡ Resolution confidence: {context.resolution_confidence:.2f}")
                
                # Show bounded depth information if available
                if hasattr(context, 'bounded_depth'):
                    logger.info(f"   📏 Hierarchy depth reached: {context.bounded_depth}/{self.max_hierarchy_depth}")
            else:
                logger.warning(f"   ❌ Could not resolve context")
        
        # Show system statistics
        stats = self.context_resolver.get_context_statistics()
        logger.info(f"\n📊 System Statistics:")
        logger.info(f"   🏗️ Context nodes: {stats['context_nodes']}")
        logger.info(f"   🌐 Global contexts: {stats['global_contexts']}")
        logger.info(f"   📏 Max hierarchy depth: {stats['max_hierarchy_depth']}")
        logger.info(f"   💾 Cached resolutions: {stats['cached_resolutions']}")
    
    def demonstrate_decision_hop_analysis(self, max_decision_hops: int = 3) -> None:
        """Demonstrate decision-hop based temporal analysis"""
        
        logger.info(f"\n🕸️ Decision-Hop Analysis Demo (max hops: {max_decision_hops})")
        logger.info("=" * 50)
        
        # Create some temporal context with decisions
        base_address = "ucxl://any:any@BZZZ:RUSTLE-testing/src/main.rs"
        
        # Initial context creation
        initial_context = {
            'summary': 'Main entry point implementing BZZZ distributed system bootstrap',
            'purpose': 'Application startup and P2P network initialization',
            'technologies': ['Rust', 'Tokio', 'P2P'],
            'tags': ['main', 'entry-point', 'rust', 'distributed'],
            'insights': ['Initializes P2P network for metadata distribution']
        }
        
        initial_node = self.temporal_graph.create_initial_context(
            base_address, initial_context, "system_analysis"
        )
        
        # Decision 1: Architecture enhancement
        arch_decision = DecisionMetadata(
            decision_maker="tony",
            decision_id="arch_001",
            decision_rationale="Enhanced P2P architecture with bounded context hierarchy",
            impact_scope="system",
            confidence_level=0.9,
            external_references=["design_doc_v2.md"]
        )
        
        arch_context = initial_context.copy()
        arch_context['insights'].append('Implements bounded hierarchy traversal for efficient context resolution')
        arch_context['technologies'].append('Bounded Context Hierarchy')
        
        arch_node = self.temporal_graph.evolve_context(
            base_address, arch_context, ContextChangeReason.ARCHITECTURE_CHANGE, arch_decision
        )
        
        # Create related addresses and decisions
        related_addresses = [
            "ucxl://any:any@BZZZ:RUSTLE-testing/src/context_resolver.rs",
            "ucxl://any:any@BZZZ:RUSTLE-testing/src/temporal_graph.rs"
        ]
        
        for i, addr in enumerate(related_addresses):
            context = {
                'summary': f'Component {i+1}: {addr.split("/")[-1]}',
                'purpose': f'Supporting component for bounded context system',
                'technologies': ['Rust', 'Context Resolution'],
                'tags': ['component', 'context-system'],
                'insights': [f'Implements part of the bounded context architecture']
            }
            
            decision = DecisionMetadata(
                decision_maker="system_analysis",
                decision_id=f"component_{i+1}",
                decision_rationale=f"Component creation for bounded context implementation",
                impact_scope="module",
                confidence_level=0.8,
                external_references=[]
            )
            
            # Create temporal context
            self.temporal_graph.evolve_context(
                addr, context, ContextChangeReason.ARCHITECTURE_CHANGE, decision
            )
            
            # Create influence relationships
            self.temporal_graph.add_influence_relationship(base_address, addr)
        
        # Demonstrate decision-hop analysis
        logger.info(f"🎯 Decision Timeline for {base_address.split('/')[-1]}:")
        
        timeline = self.temporal_graph.get_decision_timeline(
            base_address, include_related=True, max_hops=max_decision_hops
        )
        
        for decision in timeline['decision_sequence']:
            logger.info(f"   Decision #{decision['decision_hop']}: {decision['change_reason']}")
            logger.info(f"     👤 Decision maker: {decision['decision_maker']}")
            logger.info(f"     💪 Confidence: {decision['confidence_evolution']:.2f}")
            logger.info(f"     📊 Influences: {decision['influences_count']} addresses")
        
        # Show related decisions within hop distance
        if timeline['related_decisions']:
            logger.info(f"\n🔗 Related Decisions (within {max_decision_hops} hops):")
            for related in timeline['related_decisions']:
                logger.info(f"   {related['address'].split('/')[-1]} ({related['decision_hops']} hops)")
                logger.info(f"     🔄 Latest: {related['change_reason']}")
                logger.info(f"     📊 Confidence: {related['confidence']:.2f}")
        
        # Find decision paths
        logger.info(f"\n🛤️ Decision Paths:")
        for addr in related_addresses:
            path = self.temporal_graph.find_decision_path(base_address, addr)
            if path:
                path_names = [p[0].split('/')[-1] for p in path]
                logger.info(f"   {base_address.split('/')[-1]} → {' → '.join(path_names[1:])}")
    
    def save_bounded_system(self) -> None:
        """Save the complete bounded context system"""
        
        logger.info("\n💾 Saving Bounded Context System")
        logger.info("=" * 35)
        
        # Save temporal data
        self.temporal_graph.save_temporal_data()
        
        # Save global contexts
        global_file = self.metadata_base / "BZZZ" / "global_contexts.json"
        with open(global_file, 'w') as f:
            json.dump(self.context_resolver.global_contexts, f, indent=2)
        
        # Save system configuration
        config = {
            'max_hierarchy_depth': self.max_hierarchy_depth,
            'project_path': str(self.project_path),
            'metadata_base': str(self.metadata_base),
            'system_version': '1.0.0-bounded',
            'features': [
                'bounded_hierarchy_walking',
                'global_context_support',
                'decision_hop_temporal_analysis',
                'space_efficient_storage'
            ],
            'created_at': datetime.now(timezone.utc).isoformat()
        }
        
        config_file = self.metadata_base / "BZZZ" / "system_config.json"
        with open(config_file, 'w') as f:
            json.dump(config, f, indent=2)
        
        logger.info(f"✅ System saved:")
        logger.info(f"   📄 Global contexts: {global_file}")
        logger.info(f"   ⚙️ Configuration: {config_file}")
        logger.info(f"   🕸️ Temporal data: {self.temporal_graph.temporal_dir}")

def main():
    parser = argparse.ArgumentParser(description="Bounded Hierarchical Context System Demo")
    parser.add_argument("--project-path", default="/tmp/demo-bzzz-cascading",
                       help="Path to project directory")
    parser.add_argument("--metadata-base", default="/tmp/bounded-context-metadata",
                       help="Base directory for metadata storage")
    parser.add_argument("--max-depth", type=int, default=8,
                       help="Maximum hierarchy depth for bounded walking")
    parser.add_argument("--decision-hops", type=int, default=3,
                       help="Maximum decision hops for temporal analysis")
    parser.add_argument("--demo-global", action="store_true",
                       help="Demonstrate global context functionality")
    
    args = parser.parse_args()
    
    logger.info("🎬 Bounded Hierarchical Context System Demo")
    logger.info("=" * 50)
    
    # Initialize the bounded system
    bounded_system = BoundedContextSystem(
        args.project_path,
        args.metadata_base,
        args.max_depth
    )
    
    bounded_system.initialize_system()
    
    # Generate hierarchical metadata
    results = bounded_system.generate_hierarchical_metadata()
    
    # Setup global contexts if requested
    if args.demo_global:
        bounded_system.setup_global_contexts()
    
    # Demonstrate bounded resolution
    bounded_system.demonstrate_bounded_resolution()
    
    # Demonstrate decision-hop analysis
    bounded_system.demonstrate_decision_hop_analysis(args.decision_hops)
    
    # Save the system
    bounded_system.save_bounded_system()
    
    logger.info("\n✨ Demo Complete!")
    logger.info("=" * 20)
    logger.info("🎉 Bounded hierarchical context system demonstrated successfully")
    logger.info("📏 Hierarchy walking bounded to prevent excessive traversal")
    logger.info("🌐 Global contexts provide system-wide applicable metadata")
    logger.info("🕸️ Decision-hop analysis tracks conceptually related changes")
    logger.info("💾 Space-efficient storage through intelligent inheritance")

if __name__ == "__main__":
    main()