#!/usr/bin/env python3
"""
Genesis Expertise Loader
=========================
Loads expertise files (YAML mental models) before task execution.

Implements the Agent Experts pattern:
- Load expertise file for domain
- Inject mental model into context
- Track expertise usage for self-improvement

Usage:
    from expertise_loader import ExpertiseLoader

    loader = ExpertiseLoader()
    context = loader.load_for_domain("code_review")
    # Use context in your task execution

    # After task completion:
    loader.record_usage("code_review", success=True)
"""

import yaml
import json
from pathlib import Path
from datetime import datetime
from typing import Dict, Any, Optional, List
from dataclasses import dataclass, field, asdict


@dataclass
class ExpertiseContext:
    """Context loaded from expertise files."""
    domain: str
    expertise_path: Path
    mental_model: Dict[str, Any]
    loaded_at: str = field(default_factory=lambda: datetime.now().isoformat())
    usage_count: int = 0

    def to_prompt(self) -> str:
        """Convert expertise to prompt injection format."""
        return f"""# Domain Expertise: {self.domain}

## Mental Model
{yaml.dump(self.mental_model, default_flow_style=False)}

## Important
- This expertise file is a mental model, NOT the source of truth
- The CODE is always the source of truth
- Update this expertise after significant learnings
"""


class ExpertiseLoader:
    """
    Loads and manages domain expertise files.

    Expertise files are YAML documents that contain:
    - Mental models for specific domains
    - Patterns and best practices
    - Self-improvement prompts
    """

    def __init__(self, base_path: str = "/mnt/e/genesis-system/expertise"):
        self.base_path = Path(base_path)
        self.loaded_contexts: Dict[str, ExpertiseContext] = {}
        self.usage_log_path = self.base_path / "usage_log.json"
        self._load_usage_log()

    def _load_usage_log(self):
        """Load usage statistics from disk."""
        self.usage_log = {}
        if self.usage_log_path.exists():
            try:
                with open(self.usage_log_path) as f:
                    self.usage_log = json.load(f)
            except Exception:
                self.usage_log = {}

    def _save_usage_log(self):
        """Save usage statistics to disk."""
        self.usage_log_path.parent.mkdir(parents=True, exist_ok=True)
        with open(self.usage_log_path, 'w') as f:
            json.dump(self.usage_log, f, indent=2)

    def list_domains(self) -> List[str]:
        """List all available expertise domains."""
        domains = []
        if self.base_path.exists():
            for path in self.base_path.iterdir():
                if path.is_dir() and not path.name.startswith('.'):
                    domains.append(path.name)
        return sorted(domains)

    def load_for_domain(self, domain: str) -> ExpertiseContext:
        """
        Load expertise for a specific domain.

        Args:
            domain: The domain name (e.g., "code_review", "testing")

        Returns:
            ExpertiseContext with loaded mental model
        """
        # Check cache first
        if domain in self.loaded_contexts:
            ctx = self.loaded_contexts[domain]
            ctx.usage_count += 1
            return ctx

        # Find expertise file
        domain_path = self.base_path / domain
        expertise_file = None

        for ext in ['.yaml', '.yml', '.json']:
            candidate = domain_path / f"expertise{ext}"
            if candidate.exists():
                expertise_file = candidate
                break

        # Load mental model
        mental_model = {}
        if expertise_file and expertise_file.exists():
            with open(expertise_file) as f:
                if expertise_file.suffix in ['.yaml', '.yml']:
                    mental_model = yaml.safe_load(f) or {}
                else:
                    mental_model = json.load(f)

        # Create context
        ctx = ExpertiseContext(
            domain=domain,
            expertise_path=expertise_file or domain_path / "expertise.yaml",
            mental_model=mental_model,
            usage_count=1
        )

        # Cache and track
        self.loaded_contexts[domain] = ctx

        # Update usage log
        if domain not in self.usage_log:
            self.usage_log[domain] = {"loads": 0, "successes": 0, "failures": 0}
        self.usage_log[domain]["loads"] += 1
        self._save_usage_log()

        return ctx

    def load_self_improve_prompt(self, domain: str) -> Optional[str]:
        """Load the self-improvement prompt for a domain."""
        domain_path = self.base_path / domain
        prompt_file = domain_path / "self_improve.md"

        if prompt_file.exists():
            with open(prompt_file) as f:
                return f.read()
        return None

    def record_usage(self, domain: str, success: bool, notes: str = ""):
        """
        Record expertise usage outcome for self-improvement.

        Args:
            domain: The domain that was used
            success: Whether the task succeeded
            notes: Optional notes about what was learned
        """
        if domain not in self.usage_log:
            self.usage_log[domain] = {"loads": 0, "successes": 0, "failures": 0}

        if success:
            self.usage_log[domain]["successes"] += 1
        else:
            self.usage_log[domain]["failures"] += 1

        # Record notes if provided
        if notes:
            if "learnings" not in self.usage_log[domain]:
                self.usage_log[domain]["learnings"] = []
            self.usage_log[domain]["learnings"].append({
                "timestamp": datetime.now().isoformat(),
                "success": success,
                "notes": notes
            })

        self._save_usage_log()

    def get_success_rate(self, domain: str) -> float:
        """Get the success rate for a domain."""
        if domain not in self.usage_log:
            return 0.0

        stats = self.usage_log[domain]
        total = stats.get("successes", 0) + stats.get("failures", 0)
        if total == 0:
            return 0.0
        return stats.get("successes", 0) / total

    def get_stats(self) -> Dict[str, Any]:
        """Get usage statistics for all domains."""
        stats = {}
        for domain, data in self.usage_log.items():
            total = data.get("successes", 0) + data.get("failures", 0)
            stats[domain] = {
                "loads": data.get("loads", 0),
                "successes": data.get("successes", 0),
                "failures": data.get("failures", 0),
                "success_rate": data.get("successes", 0) / total if total > 0 else 0.0
            }
        return stats

    def inject_into_prompt(self, base_prompt: str, domain: str) -> str:
        """
        Inject expertise context into a prompt.

        Args:
            base_prompt: The original prompt
            domain: The domain to inject expertise from

        Returns:
            Enhanced prompt with expertise context
        """
        ctx = self.load_for_domain(domain)
        expertise_section = ctx.to_prompt()

        return f"""{expertise_section}

---

{base_prompt}

---

Remember: After completing this task, update the expertise file if you learned something new.
"""


# CLI Interface
if __name__ == "__main__":
    import sys

    if len(sys.argv) < 2:
        print("""
Genesis Expertise Loader
========================

Commands:
  list                    List available domains
  load <domain>           Load and display expertise
  stats                   Show usage statistics
  inject <domain> <text>  Inject expertise into text

Examples:
  python expertise_loader.py list
  python expertise_loader.py load code_review
  python expertise_loader.py stats
        """)
        sys.exit(0)

    loader = ExpertiseLoader()
    command = sys.argv[1]

    if command == "list":
        domains = loader.list_domains()
        print("Available Domains:")
        for domain in domains:
            rate = loader.get_success_rate(domain)
            print(f"  {domain} (success rate: {rate:.0%})")

    elif command == "load" and len(sys.argv) > 2:
        domain = sys.argv[2]
        ctx = loader.load_for_domain(domain)
        print(ctx.to_prompt())

    elif command == "stats":
        stats = loader.get_stats()
        print("Expertise Usage Statistics:")
        print(json.dumps(stats, indent=2))

    elif command == "inject" and len(sys.argv) > 3:
        domain = sys.argv[2]
        text = " ".join(sys.argv[3:])
        result = loader.inject_into_prompt(text, domain)
        print(result)

    else:
        print(f"Unknown command: {command}")
        sys.exit(1)
