# 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 time
import random

# 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

class EvolutionEngineV2:
    """
    Genesis Evolution Engine v2.0
    Processes video learnings with Gate A: P5 Consensus Validation, and includes
    performance tracking, anomaly detection, A/B testing, and automated rollback.
    """
    def __init__(self, workspace_path: str = "e:/genesis-system"):
        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.metrics_path = self.workspace / "METRICS" / "evolution_metrics.jsonl"
        self.anomaly_threshold = 0.8 # Example threshold for anomaly detection
        self.improvement_proposals = [] # List to store improvement proposals

    def process_new_video(self, video_id: str, url: str):
        """Runs youtube_learner on a video and integrates it into the KG."""
        print(f"--- Evolution Start: {video_id} ---")
        start_time = time.time()

        # 1. Trigger YouTube Learner
        cmd = ["python", str(self.workspace / "tools" / "youtube_learner.py"), "learn", url]
        result = subprocess.run(cmd, capture_output=True, text=True)
        youtube_learner_output = result.stdout
        print(youtube_learner_output)
        
        # 2. Gate A: P5 Consensus Validation (Simulated Swarm Check)
        if not self._run_p5_consensus(video_id, youtube_learner_output):
            print(f"⚠️ EVOLUTION BLOCKED: P5 Consensus Gate failed for {video_id}.")
            self._log_metric(video_id, "p5_consensus_failed", 0, time.time() - start_time)
            return

        # 3. Axiomatization
        self._generate_video_axiom(video_id, youtube_learner_output 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)

        # 6. Collect Metrics
        processing_time = time.time() - start_time
        self._log_metric(video_id, "success", 1, processing_time)

        # 7. Check for anomalies
        self._check_for_anomalies()

        # 8. Generate improvement proposals
        self._generate_improvement_proposals()

        # 9. Test improvements (A/B testing - simulated)
        if self.improvement_proposals:
            self._test_improvements()

    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 _log_metric(self, video_id: str, metric_name: str, value: float, duration: float):
        """Logs performance metrics to a file."""
        self.metrics_path.parent.mkdir(parents=True, exist_ok=True)
        metric = {
            "video_id": video_id,
            "metric": metric_name,
            "value": value,
            "timestamp": datetime.now().isoformat(),
            "duration": duration
        }
        with open(self.metrics_path, "a", encoding="utf-8") as f:
            f.write(json.dumps(metric) + "\n")

    def _load_metrics(self) -> List[Dict]:
        """Loads metrics from the metrics file."""
        if not self.metrics_path.exists():
            return []

        metrics = []
        with open(self.metrics_path, "r", encoding="utf-8") as f:
            for line in f:
                try:
                    metrics.append(json.loads(line))
                except json.JSONDecodeError:
                    print(f"Warning: Skipping invalid JSON line in {self.metrics_path}")
        return metrics

    def _check_for_anomalies(self):
        """Detects anomalies in the metrics."""
        metrics = self._load_metrics()
        if not metrics:
            return

        # Simple anomaly detection: check for unusually long processing times
        processing_times = [m["duration"] for m in metrics if m["metric"] == "success"]
        if not processing_times:
            return

        avg_processing_time = sum(processing_times) / len(processing_times)
        std_dev = (sum([(x - avg_processing_time) ** 2 for x in processing_times]) / len(processing_times)) ** 0.5

        for metric in metrics:
            if metric["metric"] == "success" and metric["duration"] > avg_processing_time + self.anomaly_threshold * std_dev:
                print(f"🚨 Anomaly Detected: Video {metric['video_id']} processing time is unusually high ({metric['duration']:.2f}s).")
                # Trigger a deeper analysis or alert

    def _generate_improvement_proposals(self):
        """Generates improvement proposals based on performance metrics."""
        # Example: If P5 consensus fails frequently, propose improving the consensus mechanism.
        metrics = self._load_metrics()
        if not metrics:
            return

        p5_failures = sum(1 for m in metrics if m["metric"] == "p5_consensus_failed")
        total_videos = len([m for m in metrics if m["metric"] in ("success", "p5_consensus_failed")])

        if total_videos > 0 and p5_failures / total_videos > 0.3:
            proposal = {
                "id": "IMP-001",
                "description": "Improve P5 Consensus Mechanism: Implement better prompt engineering or use more diverse agents.",
                "priority": "high",
                "potential_impact": "Reduce failures and improve the quality of knowledge graph entries."
            }
            if proposal not in self.improvement_proposals:
                self.improvement_proposals.append(proposal)
                print(f"💡 Improvement Proposal Generated: {proposal['description']}")

    def _test_improvements(self):
        """Tests improvement proposals using A/B testing (simulated)."""
        if not self.improvement_proposals:
            return

        for proposal in self.improvement_proposals:
            print(f"🧪 Testing Improvement Proposal: {proposal['description']}")

            # Simulate A/B testing by running a few videos with and without the improvement
            num_test_videos = 3
            successes_with_improvement = 0
            successes_without_improvement = 0

            # With improvement
            print("  Running tests *with* the improvement...")
            for _ in range(num_test_videos):
                successes_with_improvement += self._simulate_video_processing_with_improvement()

            # Without improvement (control group)
            print("  Running tests *without* the improvement...")
            for _ in range(num_test_videos):
                successes_without_improvement += self._simulate_video_processing_without_improvement()

            # Calculate success rates
            success_rate_with = successes_with_improvement / num_test_videos
            success_rate_without = successes_without_improvement / num_test_videos

            print(f"  Success Rate (with improvement): {success_rate_with:.2f}")
            print(f"  Success Rate (without improvement): {success_rate_without:.2f}")

            # Evaluate the results
            if success_rate_with > success_rate_without + 0.1:  # Significant improvement
                print("🚀 Improvement deployed: Success rate significantly increased.")
                self._deploy_improvement(proposal)
            else:
                print("❌ Improvement rolled back: No significant improvement detected.")
                self._rollback_improvement(proposal)

    def _simulate_video_processing_with_improvement(self) -> int:
        """Simulates video processing with the proposed improvement."""
        # This would involve modifying the code to implement the improvement
        # For now, we just simulate the outcome
        return random.choices([0, 1], weights=[0.1, 0.9])[0]  # 90% success rate

    def _simulate_video_processing_without_improvement(self) -> int:
        """Simulates video processing without the proposed improvement (control)."""
        # This represents the baseline performance
        return random.choices([0, 1], weights=[0.2, 0.8])[0]  # 80% success rate

    def _deploy_improvement(self, proposal: Dict):
        """Deploys the improvement (simulated)."""
        print(f"✅ Deploying improvement: {proposal['description']}")
        # In a real system, this would involve updating the code or configuration
        # and restarting the relevant services.

    def _rollback_improvement(self, proposal: Dict):
        """Rolls back the improvement (simulated)."""
        print(f"⏪ Rolling back improvement: {proposal['description']}")
        # In a real system, this would involve reverting the code or configuration
        # to the previous state.

if __name__ == "__main__":
    engine = EvolutionEngineV2()
    engine.process_new_video("vqHBfe3r4OQ", "https://www.youtube.com/watch?v=vqHBfe3r4OQ")
    engine.process_new_video("another_video", "https://www.youtube.com/watch?v=another_video")
    engine.process_new_video("third_video", "https://www.youtube.com/watch?v=third_video")