#!/usr/bin/env python3
"""
Genesis Master Orchestrator
============================
Central command for autonomous Genesis operations.
Authority Level: L4 (Full Autonomous Evolution)

Per user mandate and Prime Directive, this orchestrator operates
with full autonomous authority for all routine operations.
"""

import os
import sys
import json
from datetime import datetime, timezone
from dataclasses import dataclass, field
from typing import Dict, List, Optional, Any
from enum import Enum
from pathlib import Path

# Ensure genesis-memory is in path
sys.path.insert(0, "/mnt/e/genesis-system/genesis-memory")


class AuthorityLevel(Enum):
    """Authority levels for decision-making."""
    L1_EXECUTE = 1      # Direct skill invocation
    L2_COORDINATE = 2   # Multi-skill orchestration
    L3_DECIDE = 3       # Goal decomposition
    L4_EVOLVE = 4       # Self-improvement (DEFAULT)
    L5_ARCHITECT = 5    # Major changes (requires escalation)


class TaskStatus(Enum):
    """Task execution states."""
    PENDING = "pending"
    IN_PROGRESS = "in_progress"
    TESTING = "testing"
    COMPLETE = "complete"
    FAILED = "failed"
    SKIPPED = "skipped"


@dataclass
class Skill:
    """Represents a Genesis skill."""
    name: str
    path: str
    commands: List[str] = field(default_factory=list)
    description: str = ""
    active: bool = True


@dataclass
class MasteryTask:
    """Represents a task from CC-MASTERY-TASKS.md."""
    number: int
    name: str
    description: str
    status: TaskStatus = TaskStatus.PENDING
    priority: str = "medium"
    started_at: Optional[str] = None
    completed_at: Optional[str] = None
    result: Optional[str] = None


@dataclass
class Decision:
    """Logged decision for audit trail."""
    decision_id: str
    timestamp: str
    authority_level: AuthorityLevel
    action: str
    rationale: str
    outcome: Optional[str] = None
    escalated: bool = False


class MasterOrchestrator:
    """
    Genesis Master Orchestrator - Central autonomous command.

    Operates at Authority Level L4 (Full Autonomous Evolution)
    per user mandate and Prime Directive.
    """

    SKILLS_DIR = os.path.expanduser("~/.claude/plugins")
    STATE_FILE = "/mnt/e/genesis-system/config/orchestrator_state.json"
    TASKS_FILE = "/mnt/e/genesis-system/CC-MASTERY-TASKS.md"

    # Default authority level
    AUTHORITY_LEVEL = AuthorityLevel.L4_EVOLVE

    # Escalation threshold
    CAPITAL_THRESHOLD = 50.0  # $50/month

    def __init__(self):
        self.skills: Dict[str, Skill] = {}
        self.tasks: Dict[int, MasteryTask] = {}
        self.decisions: List[Decision] = []
        self.evolution_components: Dict[str, bool] = {}

        self._discover_skills()
        self._load_tasks()
        self._check_evolution_components()
        self._load_state()

    def _discover_skills(self) -> None:
        """Scan for installed Genesis skills."""
        if not os.path.exists(self.SKILLS_DIR):
            return

        for item in os.listdir(self.SKILLS_DIR):
            if item.startswith("genesis-"):
                skill_path = os.path.join(self.SKILLS_DIR, item)
                if os.path.isdir(skill_path):
                    skill_name = item.replace("genesis-", "")

                    # Discover commands
                    commands = []
                    cmd_dir = os.path.join(skill_path, "commands")
                    if os.path.exists(cmd_dir):
                        for cmd_file in os.listdir(cmd_dir):
                            if cmd_file.endswith(".md"):
                                commands.append(cmd_file.replace(".md", ""))

                    # Read description from plugin.json
                    description = ""
                    plugin_json = os.path.join(skill_path, ".claude-plugin", "plugin.json")
                    if os.path.exists(plugin_json):
                        try:
                            with open(plugin_json) as f:
                                plugin_data = json.load(f)
                                description = plugin_data.get("description", "")
                        except:
                            pass

                    self.skills[skill_name] = Skill(
                        name=skill_name,
                        path=skill_path,
                        commands=commands,
                        description=description
                    )

    def _load_tasks(self) -> None:
        """Load mastery tasks from CC-MASTERY-TASKS.md."""
        # Pre-defined task list
        task_definitions = {
            0: ("GHL Research", "Locate Genesis GHL knowledge base", "complete"),
            1: ("Letta Architecture Deep Dive", "Dissect Letta core", "skipped"),
            2: ("Letta Advanced Memory Patterns", "Implement memory types", "skipped"),
            3: ("Letta Multi-Agent Communication", "Create coordinating agents", "skipped"),
            4: ("Letta Tool Integration", "Connect to MCP servers", "skipped"),
            5: ("Letta Verdict", "Write comprehensive report", "complete"),
            6: ("LangChain Core Patterns Catalog", "Implement every pattern", "pending"),
            7: ("LangGraph Multi-Agent Systems", "Build 3 architectures", "pending"),
            8: ("RAG Pattern Mastery", "Implement 5+ RAG variations", "pending"),
            9: ("LangChain Tool Ecosystem", "Integrate with MCP", "pending"),
            10: ("Alternative Frameworks Survey", "Test CrewAI, AutoGen, etc", "pending"),
            11: ("MCP Server Complete Catalog", "List every MCP server", "pending"),
            12: ("MCP Batch 1 (Productivity)", "Notion, Slack, Gmail, etc", "pending"),
            13: ("MCP Batch 2 (Development)", "Docker, Postgres, etc", "pending"),
            14: ("MCP Batch 3 (Data & AI)", "Vector DBs, analytics", "pending"),
            15: ("MCP Batch 4 (Specialized)", "Niche servers", "pending"),
            16: ("Custom MCP Development Learning", "Study MCP protocol", "pending"),
            17: ("Genesis Memory System 2.0", "Integrate best patterns", "complete"),
            18: ("Genesis Self-Evolution Test", "Build self-improving agent", "complete"),
        }

        for num, (name, desc, status) in task_definitions.items():
            self.tasks[num] = MasteryTask(
                number=num,
                name=name,
                description=desc,
                status=TaskStatus(status),
                priority="high" if num in [6, 7, 8, 11] else "medium"
            )

    def _check_evolution_components(self) -> None:
        """Check availability of evolution components."""
        components = [
            ("evolution_protocol", "agents.evolution_protocol", "get_protocol"),
            ("self_improvement_loop", "agents.self_improvement_loop", "get_improvement_loop"),
            ("voi_scoring", "intelligence.voi_scoring", "get_voi_scorer"),
            ("knowledge_synthesis", "intelligence.knowledge_synthesis", "get_knowledge_synthesizer"),
        ]

        for name, module, func in components:
            try:
                exec(f"from {module} import {func}")
                self.evolution_components[name] = True
            except ImportError:
                self.evolution_components[name] = False

    def _load_state(self) -> None:
        """Load persisted orchestrator state."""
        if os.path.exists(self.STATE_FILE):
            try:
                with open(self.STATE_FILE) as f:
                    state = json.load(f)
                    # Update task statuses from state
                    for num_str, status in state.get("task_statuses", {}).items():
                        num = int(num_str)
                        if num in self.tasks:
                            self.tasks[num].status = TaskStatus(status)
            except:
                pass

    def _save_state(self) -> None:
        """Persist orchestrator state."""
        state = {
            "task_statuses": {
                str(num): task.status.value
                for num, task in self.tasks.items()
            },
            "last_updated": datetime.now(timezone.utc).isoformat()
        }

        os.makedirs(os.path.dirname(self.STATE_FILE), exist_ok=True)
        with open(self.STATE_FILE, 'w') as f:
            json.dump(state, f, indent=2)

    def get_status(self) -> Dict[str, Any]:
        """Get comprehensive orchestrator status."""
        pending_tasks = [t for t in self.tasks.values() if t.status == TaskStatus.PENDING]
        complete_tasks = [t for t in self.tasks.values() if t.status == TaskStatus.COMPLETE]

        return {
            "authority_level": self.AUTHORITY_LEVEL.name,
            "skills_count": len(self.skills),
            "skills": list(self.skills.keys()),
            "evolution_components": self.evolution_components,
            "tasks_total": len(self.tasks),
            "tasks_pending": len(pending_tasks),
            "tasks_complete": len(complete_tasks),
            "next_task": self.get_next_task(),
            "timestamp": datetime.now(timezone.utc).isoformat()
        }

    def get_next_task(self) -> Optional[MasteryTask]:
        """Get the next pending task."""
        pending = [t for t in self.tasks.values() if t.status == TaskStatus.PENDING]
        if pending:
            # Sort by task number
            pending.sort(key=lambda t: t.number)
            return pending[0]
        return None

    def start_task(self, task_number: int) -> bool:
        """Mark a task as in progress."""
        if task_number in self.tasks:
            task = self.tasks[task_number]
            task.status = TaskStatus.IN_PROGRESS
            task.started_at = datetime.now(timezone.utc).isoformat()
            self._save_state()
            self._log_decision(
                action=f"Started task {task_number}: {task.name}",
                rationale="Next pending task in queue"
            )
            return True
        return False

    def complete_task(self, task_number: int, result: str = "") -> bool:
        """Mark a task as complete."""
        if task_number in self.tasks:
            task = self.tasks[task_number]
            task.status = TaskStatus.COMPLETE
            task.completed_at = datetime.now(timezone.utc).isoformat()
            task.result = result
            self._save_state()
            self._log_decision(
                action=f"Completed task {task_number}: {task.name}",
                rationale=result or "Task execution finished"
            )
            return True
        return False

    def should_escalate(self, action: str, capital_cost: float = 0) -> bool:
        """
        Determine if an action requires escalation.

        Per Prime Directive:
        - Capital >$50/month: ESCALATE
        - Ambiguous strategic: ESCALATE
        - Everything else: AUTONOMOUS
        """
        if capital_cost > self.CAPITAL_THRESHOLD:
            return True

        # Check for strategic ambiguity keywords
        strategic_keywords = [
            "pivot", "major change", "architecture overhaul",
            "strategic direction", "fundamental shift"
        ]
        for keyword in strategic_keywords:
            if keyword.lower() in action.lower():
                return True

        return False

    def _log_decision(
        self,
        action: str,
        rationale: str,
        escalated: bool = False
    ) -> Decision:
        """Log a decision for audit trail."""
        decision = Decision(
            decision_id=f"dec_{len(self.decisions)+1:04d}",
            timestamp=datetime.now(timezone.utc).isoformat(),
            authority_level=self.AUTHORITY_LEVEL,
            action=action,
            rationale=rationale,
            escalated=escalated
        )
        self.decisions.append(decision)
        return decision

    def generate_report(self) -> str:
        """Generate comprehensive status report."""
        status = self.get_status()

        lines = [
            "=" * 70,
            "GENESIS MASTER ORCHESTRATOR - STATUS REPORT",
            "=" * 70,
            f"Generated: {status['timestamp']}",
            f"Authority Level: {status['authority_level']}",
            "",
            "-" * 70,
            "SKILLS",
            "-" * 70,
        ]

        for skill_name in sorted(status['skills']):
            skill = self.skills[skill_name]
            lines.append(f"  /{skill_name}: {len(skill.commands)} commands")

        lines.extend([
            "",
            "-" * 70,
            "EVOLUTION COMPONENTS",
            "-" * 70,
        ])

        for comp, active in status['evolution_components'].items():
            status_str = "ACTIVE" if active else "OFFLINE"
            lines.append(f"  {comp}: {status_str}")

        lines.extend([
            "",
            "-" * 70,
            "TASK PROGRESS",
            "-" * 70,
            f"  Total: {status['tasks_total']}",
            f"  Complete: {status['tasks_complete']}",
            f"  Pending: {status['tasks_pending']}",
        ])

        if status['next_task']:
            lines.append(f"  Next: Task {status['next_task'].number} - {status['next_task'].name}")

        lines.extend([
            "",
            "=" * 70,
        ])

        return "\n".join(lines)


# Singleton instance
_orchestrator: Optional[MasterOrchestrator] = None


def get_orchestrator() -> MasterOrchestrator:
    """Get or create the master orchestrator instance."""
    global _orchestrator
    if _orchestrator is None:
        _orchestrator = MasterOrchestrator()
    return _orchestrator


if __name__ == "__main__":
    orchestrator = get_orchestrator()
    print(orchestrator.generate_report())
