# evolution_engine_v2.py
import json
import subprocess
from pathlib import Path
from typing import List, Dict, Optional
import sys
from datetime import datetime
import random
import time

# Add core to sys.path
sys.path.append("e:/genesis-system/core")

try:
    from genesis_heartbeat import AxiomGenerator, SurpriseEvent, SurpriseLevel
except ImportError:
    # Minimal stubs if imports fail
    class SurpriseLevel:
        SURPRISING = "surprising"
    class SurpriseEvent:
        def __init__(self, **kwargs):
            self.__dict__.update(kwargs)
    class AxiomGenerator:
        def __init__(self): pass
        def generate_axiom(self, *args, **kwargs): return None

# Import Reflexion Decorator
try:
    from reflexion import reflexion_loop
except ImportError:
    def reflexion_loop(max_retries: int = 2):
        def decorator(func):
            def wrapper(*args, **kwargs):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    print(f"Error in {func.__name__}: {e}")
                    raise e
            return wrapper
        return decorator

class EvolutionEngineV2:
    """
    Genesis Evolution Engine v2.0
    Includes:
    - Performance tracking
    - Anomaly detection
    - A/B testing
    - Automated rollback
    - Learning from failures
    """
    def __init__(self, workspace_path: str = "e:/genesis-system", baseline_performance: float = 0.7):
        self.workspace = Path(workspace_path)
        self.kg_entities = self.workspace / "KNOWLEDGE_GRAPH" / "entities.jsonl"
        self.market_pathways = self.workspace / "KNOWLEDGE_GRAPH" / "MARKET_PATHWAYS.md"
        self.axiom_gen = AxiomGenerator()
        self.performance_data = []  # List of tuples: (timestamp, performance_metric)
        self.anomaly_threshold = 0.1 # 10% deviation from baseline
        self.baseline_performance = baseline_performance
        self.current_version = "1.0"
        self.improvement_log = [] # (timestamp, proposal, success, details)

    def process_new_video(self, video_id: str, url: str):
        """Main entrypoint for processing a new video."""
        print(f"--- Evolution Start (v{self.current_version}): {video_id} ---")

        # 1. Initial Performance Measurement
        initial_performance = self._measure_performance()

        # 2. Run the core video processing pipeline
        try:
            self._process_video_pipeline(video_id, url)
            success = True
        except Exception as e:
            print(f"Error during video processing: {e}")
            success = False

        # 3. Post-processing performance measurement
        final_performance = self._measure_performance()

        # 4. Track performance and detect anomalies
        self._track_performance(final_performance)
        anomaly = self._detect_anomaly()

        # 5. Propose improvements if necessary
        if anomaly or not success:
            improvement_proposal = self._generate_improvement_proposal(video_id, initial_performance, final_performance, success)
            if improvement_proposal:
                # 6. Test the improvement (A/B testing)
                test_result = self._test_improvement(improvement_proposal)

                if test_result["success"]:
                    # 7. Deploy the improvement
                    self._deploy_improvement(improvement_proposal)
                    self.improvement_log.append((datetime.now().isoformat(), improvement_proposal, True, test_result))
                    print("🚀 Improvement deployed!")
                else:
                    # 8. Rollback if the improvement failed
                    self._rollback_improvement(improvement_proposal)
                    self.improvement_log.append((datetime.now().isoformat(), improvement_proposal, False, test_result))
                    print("❌ Improvement rolled back.")
            else:
                print("No improvement proposal generated.")
        else:
            print("No anomalies detected, no improvement needed.")

    @reflexion_loop(max_retries=3)
    def _process_video_pipeline(self, video_id: str, url: str):
         # 1. Trigger YouTube Learner
        cmd = ["python", str(self.workspace / "tools" / "youtube_learner.py"), "learn", url]
        result = subprocess.run(cmd, capture_output=True, text=True)
        print(result.stdout)
        
        # 2. Gate A: P5 Consensus Validation (Simulated Swarm Check)
        if not self._run_p5_consensus(video_id, result.stdout):
            print(f"⚠️ EVOLUTION BLOCKED: P5 Consensus Gate failed for {video_id}.")
            raise ValueError("P5 Consensus Failed")

        # 3. Axiomatization
        self._generate_video_axiom(video_id, result.stdout or "No transcript available")
        
        # 4. Inject into Knowledge Graph
        self._inject_into_kg(video_id)
        
        # 5. Trigger Revenue Pathway Discovery
        self._propose_revenue_pipeline(video_id)

    def _run_p5_consensus(self, video_id: str, content: str) -> bool:
        """
        Hardening Gate A: Multi-agent consensus.
        Requires CONSENSUS_01 and CONSENSUS_02 to validate the finding.
        """
        print(f"🕵️ Gate A: running CONSENSUS_01 & CONSENSUS_02 audit on {video_id}...")
        
        # In production, this would trigger two LLM calls with different system prompts
        # Agent 1: Optimistic (looking for value)
        # Agent 2: Skeptical (looking for hallucinations)
        
        agent_audit_1 = True # Simulated pass
        agent_audit_2 = True # Simulated pass
        
        consensus_reached = agent_audit_1 and agent_audit_2
        if consensus_reached:
            print(f"✅ P5 Consensus Reached: Findings for {video_id} are valid.")
        return consensus_reached

    def _generate_video_axiom(self, video_id: str, content: str):
        """Creates a patent-aligned axiom from video content."""
        try:
            event = SurpriseEvent(
                event_id=f"YT_{video_id}",
                content=content[:500],
                source=f"youtube_{video_id}",
                timestamp=datetime.now().isoformat(),
                total_surprise=0.8,
                should_generate_axiom=True,
                level=SurpriseLevel.SURPRISING,
                prediction_error=0.5
            )
            
            print(f"Generating Axiom for {video_id}...")
            axiom = self.axiom_gen.generate_axiom(event, content, domain="technical_evolution")
            if axiom:
                print(f"✓ Axiom Generated: {axiom.statement}")
            else:
                print("! Axiom generation deferred (duplicate or key missing)")
        except Exception as e:
            print(f"✗ Axiom Generation failed: {e}")

    def _inject_into_kg(self, video_id: str):
        self.kg_entities.parent.mkdir(parents=True, exist_ok=True)
        new_node = {
            "id": f"YT_{video_id}",
            "type": "technology_enabler",
            "source": f"youtube_{video_id}",
            "relevance": "high",
            "patent_synergy": "P4, P7",
            "timestamp": datetime.now().isoformat()
        }
        with open(self.kg_entities, "a", encoding="utf-8") as f:
            f.write(json.dumps(new_node) + "\n")

    def _propose_revenue_pipeline(self, video_id: str):
        if not self.market_pathways.exists():
            with open(self.market_pathways, "w", encoding="utf-8") as f:
                f.write("# Genesis Market Pathways\n\n")

        proposal = f"""
## Autonomous Pipeline Proposal (from YT_{video_id})
- **Concept**: Revenue Stream from new AI tools discovered via scout agent.
- **Target**: Founder Revenue Pipeline
- **Status**: GATED (Awaiting Founder Approval)
- **Hardening**: Verified by P5 Swarm Consensus.
- **Timestamp**: {datetime.now().isoformat()}
"""
        with open(self.market_pathways, "a", encoding="utf-8") as f:
            f.write(proposal)

    def _measure_performance(self) -> float:
        """
        Simulates performance measurement.  In reality, this would
        query some monitoring system or database.
        """
        # Simulate a performance metric between 0.5 and 1.0
        performance = random.uniform(0.5, 1.0)
        print(f"Measured Performance: {performance}")
        return performance

    def _track_performance(self, performance_metric: float):
        """Tracks performance over time."""
        self.performance_data.append((datetime.now().isoformat(), performance_metric))

    def _detect_anomaly(self) -> bool:
        """Detects anomalies based on deviation from the baseline."""
        if not self.performance_data:
            return False

        latest_performance = self.performance_data[-1][1]
        deviation = abs(latest_performance - self.baseline_performance) / self.baseline_performance
        if deviation > self.anomaly_threshold:
            print(f"⚠️ Anomaly Detected! Deviation from baseline: {deviation:.2f}")
            return True
        else:
            return False

    def _generate_improvement_proposal(self, video_id: str, initial_performance: float, final_performance: float, success: bool) -> Optional[Dict]:
        """
        Generates a proposal for improvement.  This could involve
        changing parameters, updating models, etc.
        """
        # Example: If performance decreased, suggest increasing the verbosity of youtube_learner
        if final_performance < initial_performance:
            proposal = {
                "type": "parameter_change",
                "component": "youtube_learner",
                "parameter": "verbosity",
                "old_value": "normal",
                "new_value": "high",
                "reason": f"Performance decreased after processing video {video_id}"
            }
            return proposal
        elif not success:
            proposal = {
                "type": "code_fix",
                "component": "p5_consensus",
                "description": "Address potential errors in P5 consensus logic.",
                "reason": f"Video processing failed for {video_id}"
            }
            return proposal
        else:
            return None

    def _test_improvement(self, improvement_proposal: Dict) -> Dict:
        """
        Tests the proposed improvement using A/B testing or other methods.
        """
        print(f"🧪 Testing Improvement: {improvement_proposal}")
        # Simulate a test run.
        time.sleep(1)
        success = random.random() > 0.2 # 80% chance of success
        
        if success:
            score = random.uniform(0.7, 1.0)
            print(f"Test Successful. Score: {score}")
            return {"success": True, "score": score, "details": "A/B test passed."}
        else:
            print("Test Failed.")
            return {"success": False, "error": "A/B test failed.", "details": "Performance did not improve."}

    def _deploy_improvement(self, improvement_proposal: Dict):
        """Deploys the improvement to the system."""
        print(f"🚀 Deploying Improvement: {improvement_proposal}")
        # Simulate deployment.  In a real system, this might involve
        # updating configuration files, restarting services, etc.
        if improvement_proposal["type"] == "parameter_change":
            self.current_version = f"{float(self.current_version) + 0.1}"
            print(f"Updated version to {self.current_version}")

    def _rollback_improvement(self, improvement_proposal: Dict):
        """Rolls back a failed improvement."""
        print(f"❌ Rolling Back Improvement: {improvement_proposal}")
        if improvement_proposal["type"] == "parameter_change":
            self.current_version = f"{float(self.current_version) - 0.1}"
            print(f"Rolled back version to {self.current_version}")
        # In a real system, this would revert the changes made during deployment.

    def _learn_from_failure(self, video_id: str, error: str):
        """
        Learns from failures and updates the improvement proposal generation logic.
        """
        print(f"Learning from failure for video {video_id}: {error}")
        # In a real system, this could involve updating the weights of
        # different improvement strategies based on their past performance.

if __name__ == "__main__":
    engine = EvolutionEngineV2()
    engine.process_new_video("vqHBfe3r4OQ", "https://www.youtube.com/watch?v=vqHBfe3r4OQ")
    print("\n--- Processing another video ---")
    engine.process_new_video("another_video", "https://www.youtube.com/watch?v=example")
    print("\n--- Improvement Log ---")
    for log in engine.improvement_log:
        print(log)