#!/usr/bin/env python3
"""
Luz Server Orchestrator

Single-process orchestrator that routes requests to project-specific subagents.
Replaces multiple Claude sessions with one efficient coordinator.

Usage:
    # Interactive mode
    python orchestrator.py

    # Single task
    python orchestrator.py -p "Check overbits build status"

    # Specific project
    python orchestrator.py --project overbits -p "Run tests"
"""

import json
import subprocess
import sys
import os
from pathlib import Path
from typing import Optional, Dict, Any
from dataclasses import dataclass
from datetime import datetime

CONFIG_PATH = Path(__file__).parent / "config.json"
LOG_DIR = Path("/var/log/claude-orchestrator")

@dataclass
class ProjectConfig:
    path: str
    description: str
    subagent_model: str
    tools: list
    focus: str

class Orchestrator:
    def __init__(self):
        self.config = self._load_config()
        self.projects: Dict[str, ProjectConfig] = {}
        self._parse_projects()

    def _load_config(self) -> dict:
        """Load orchestrator configuration"""
        if CONFIG_PATH.exists():
            with open(CONFIG_PATH) as f:
                return json.load(f)
        return {"projects": {}}

    def _parse_projects(self):
        """Parse project configurations"""
        for name, cfg in self.config.get("projects", {}).items():
            self.projects[name] = ProjectConfig(
                path=cfg.get("path", f"/home/{name}"),
                description=cfg.get("description", ""),
                subagent_model=cfg.get("subagent_model", "haiku"),
                tools=cfg.get("tools", ["Read", "Glob", "Grep"]),
                focus=cfg.get("focus", "")
            )

    def detect_project(self, prompt: str) -> Optional[str]:
        """Detect which project a prompt relates to"""
        prompt_lower = prompt.lower()

        # Direct mentions
        for name in self.projects:
            if name in prompt_lower:
                return name

        # Path mentions
        for name, cfg in self.projects.items():
            if cfg.path in prompt:
                return name

        # Keyword matching
        keywords = {
            "admin": ["server", "nginx", "systemd", "user", "mcp"],
            "overbits": ["frontend", "react", "typescript", "vite"],
            "musica": ["music", "strudel", "pattern", "audio"],
            "dss": ["signature", "crypto", "certificate"],
            "librechat": ["chat", "librechat", "conversation"],
            "bbot": ["trading", "bot", "market"]
        }

        for name, kws in keywords.items():
            if name in self.projects:
                for kw in kws:
                    if kw in prompt_lower:
                        return name

        return None

    def run_subagent(self, project: str, prompt: str,
                     tools: Optional[list] = None,
                     model: Optional[str] = None) -> dict:
        """Run a subagent for a specific project"""
        cfg = self.projects.get(project)
        if not cfg:
            return {"error": f"Unknown project: {project}"}

        # Use config defaults or overrides
        agent_tools = tools or cfg.tools
        agent_model = model or cfg.subagent_model

        # Build the prompt with project context
        full_prompt = f"""You are a subagent for the {project} project.

Working directory: {cfg.path}
Focus: {cfg.focus}
Description: {cfg.description}

Task: {prompt}

Execute this task efficiently and return a concise summary."""

        try:
            result = subprocess.run(
                [
                    "claude",
                    "-p", full_prompt,
                    "--output-format", "json",
                    "--allowedTools", ",".join(agent_tools),
                    "--model", agent_model
                ],
                cwd=cfg.path,
                capture_output=True,
                text=True,
                timeout=300
            )

            try:
                return json.loads(result.stdout)
            except json.JSONDecodeError:
                return {
                    "result": result.stdout,
                    "stderr": result.stderr,
                    "returncode": result.returncode
                }

        except subprocess.TimeoutExpired:
            return {"error": "Task timed out after 5 minutes"}
        except Exception as e:
            return {"error": str(e)}

    def route_request(self, prompt: str) -> dict:
        """Route a request to the appropriate subagent"""
        project = self.detect_project(prompt)

        if project:
            print(f"[Orchestrator] Routing to {project} subagent...")
            return self.run_subagent(project, prompt)
        else:
            # Multi-project or general request
            print("[Orchestrator] No specific project detected, running general task...")
            return self._run_general(prompt)

    def _run_general(self, prompt: str) -> dict:
        """Run a general task not specific to any project"""
        result = subprocess.run(
            [
                "claude",
                "-p", prompt,
                "--output-format", "json",
                "--allowedTools", "Read,Glob,Grep,Bash"
            ],
            cwd="/home/admin",
            capture_output=True,
            text=True,
            timeout=300
        )

        try:
            return json.loads(result.stdout)
        except:
            return {"result": result.stdout}

    def health_check_all(self) -> dict:
        """Run health checks across all projects"""
        results = {}
        for name in self.projects:
            print(f"[Health Check] {name}...")
            results[name] = self.run_subagent(
                name,
                "Quick health check: verify project status, check for errors",
                tools=["Read", "Glob", "Bash"]
            )
        return results

    def list_projects(self) -> None:
        """List all configured projects"""
        print("\n=== Configured Projects ===\n")
        for name, cfg in self.projects.items():
            print(f"  {name}:")
            print(f"    Path: {cfg.path}")
            print(f"    Model: {cfg.subagent_model}")
            print(f"    Focus: {cfg.focus}")
            print()

def main():
    import argparse

    parser = argparse.ArgumentParser(description="Luz Server Orchestrator")
    parser.add_argument("-p", "--prompt", help="Task prompt to execute")
    parser.add_argument("--project", help="Specific project to target")
    parser.add_argument("--list", action="store_true", help="List projects")
    parser.add_argument("--health", action="store_true", help="Health check all")

    args = parser.parse_args()

    orch = Orchestrator()

    if args.list:
        orch.list_projects()
    elif args.health:
        results = orch.health_check_all()
        print(json.dumps(results, indent=2))
    elif args.prompt:
        if args.project:
            result = orch.run_subagent(args.project, args.prompt)
        else:
            result = orch.route_request(args.prompt)
        print(json.dumps(result, indent=2))
    else:
        # Interactive mode
        print("Luz Orchestrator - Type 'quit' to exit, 'list' for projects")
        while True:
            try:
                prompt = input("\n> ").strip()
                if prompt.lower() == 'quit':
                    break
                elif prompt.lower() == 'list':
                    orch.list_projects()
                elif prompt.lower() == 'health':
                    results = orch.health_check_all()
                    print(json.dumps(results, indent=2))
                elif prompt:
                    result = orch.route_request(prompt)
                    print(json.dumps(result, indent=2))
            except KeyboardInterrupt:
                print("\nExiting...")
                break

if __name__ == "__main__":
    main()
