#!/usr/bin/env python3
"""
Smart Flow Integration - Bridges SmartRouter with Luzia's dispatch flow.

Integrates Gemini 3 Flash decision making at key points:
1. Pre-dispatch: Analyze complexity, select optimal agent
2. Mid-execution: Validate progress, adjust strategy
3. Post-execution: Validate output, decide on follow-up

This module provides the glue between SmartRouter and existing components.
"""

import json
import logging
import os
import time
from pathlib import Path
from typing import Dict, Any, Optional, Tuple
from dataclasses import dataclass

# Import SmartRouter
try:
    from smart_router import SmartRouter, RoutingDecision, ValidationResult, TaskComplexity, AgentTier
    SMART_ROUTER_AVAILABLE = True
except ImportError:
    SMART_ROUTER_AVAILABLE = False

# Import existing components
try:
    from flow_intelligence import FlowIntelligence
    FLOW_INTELLIGENCE_AVAILABLE = True
except ImportError:
    FLOW_INTELLIGENCE_AVAILABLE = False

try:
    from semantic_router import SemanticRouter
    SEMANTIC_ROUTER_AVAILABLE = True
except ImportError:
    SEMANTIC_ROUTER_AVAILABLE = False

logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
logger = logging.getLogger(__name__)


@dataclass
class EnhancedDispatchContext:
    """Enhanced context for smart dispatch."""
    task: str
    project: str
    routing_decision: Optional[RoutingDecision]
    domain_context: Optional[Dict[str, Any]]
    flow_context: Optional[Dict[str, Any]]
    model_override: Optional[str] = None
    priority: int = 5
    tags: list = None


class SmartFlowOrchestrator:
    """
    Orchestrates intelligent task dispatch using SmartRouter.

    Combines:
    - SmartRouter for Gemini-powered decisions
    - SemanticRouter for domain context
    - FlowIntelligence for task flow management
    """

    def __init__(self, config_path: Optional[Path] = None):
        """Initialize smart flow orchestrator.

        Args:
            config_path: Path to routing.yaml config
        """
        self.config_path = config_path or Path("/opt/server-agents/claude-flow/config/routing.yaml")
        self.config = self._load_config()

        # Initialize components
        self.smart_router = None
        self.semantic_router = None
        self.flow_intelligence = None

        self._init_components()

        logger.info("SmartFlowOrchestrator initialized")
        logger.info(f"  SmartRouter: {self.smart_router is not None}")
        logger.info(f"  SemanticRouter: {self.semantic_router is not None}")
        logger.info(f"  FlowIntelligence: {self.flow_intelligence is not None}")

    def _load_config(self) -> Dict[str, Any]:
        """Load routing configuration."""
        if not self.config_path.exists():
            logger.warning(f"Config not found: {self.config_path}")
            return {}

        try:
            import yaml
            return yaml.safe_load(self.config_path.read_text())
        except ImportError:
            # Fallback: basic parsing
            logger.warning("PyYAML not available, using defaults")
            return {}
        except Exception as e:
            logger.warning(f"Failed to load config: {e}")
            return {}

    def _init_components(self) -> None:
        """Initialize all routing components."""
        if SMART_ROUTER_AVAILABLE:
            try:
                self.smart_router = SmartRouter()
            except Exception as e:
                logger.warning(f"Failed to init SmartRouter: {e}")

        if SEMANTIC_ROUTER_AVAILABLE:
            try:
                self.semantic_router = SemanticRouter()
            except Exception as e:
                logger.warning(f"Failed to init SemanticRouter: {e}")

        if FLOW_INTELLIGENCE_AVAILABLE:
            try:
                self.flow_intelligence = FlowIntelligence()
            except Exception as e:
                logger.warning(f"Failed to init FlowIntelligence: {e}")

    def prepare_dispatch(self, task: str, project: str,
                        context: Dict[str, Any] = None) -> EnhancedDispatchContext:
        """
        Prepare enhanced dispatch context with smart routing.

        Args:
            task: Task description
            project: Target project
            context: Additional context

        Returns:
            EnhancedDispatchContext with routing decisions
        """
        start_time = time.time()

        # Get routing decision from SmartRouter
        routing_decision = None
        if self.smart_router:
            routing_decision = self.smart_router.analyze_and_route(task, project, context)
            logger.info(f"SmartRouter: {routing_decision.complexity.value} -> {routing_decision.recommended_agent.value}")

        # Get domain context from SemanticRouter
        domain_context = None
        if self.semantic_router:
            domain_result = self.semantic_router.route(task)
            domain_context = {
                "domain": domain_result.get("primary_domain"),
                "confidence": domain_result.get("confidence", 0),
                "best_practices": domain_result.get("best_practices", []),
                "system_instructions": domain_result.get("system_instructions", "")
            }
            logger.info(f"SemanticRouter: {domain_context['domain']} (conf: {domain_context['confidence']:.2f})")

        # Get flow context from FlowIntelligence
        flow_context = None
        if self.flow_intelligence:
            recent_flows = self.flow_intelligence.get_recent_flows(project, limit=3)
            flow_context = {
                "recent_tasks": [f.task_description[:100] for f in recent_flows],
                "active_flows": len(self.flow_intelligence.active_flows),
                "completion_rate": self.flow_intelligence.get_stats().get("completion_rate", 0)
            }

        # Determine model override based on routing
        model_override = self._determine_model(routing_decision, context)

        elapsed = time.time() - start_time
        logger.info(f"Dispatch prepared in {elapsed*1000:.1f}ms")

        return EnhancedDispatchContext(
            task=task,
            project=project,
            routing_decision=routing_decision,
            domain_context=domain_context,
            flow_context=flow_context,
            model_override=model_override,
            priority=self._calculate_priority(routing_decision),
            tags=self._extract_tags(task, domain_context)
        )

    def _determine_model(self, routing: Optional[RoutingDecision],
                        context: Dict[str, Any] = None) -> Optional[str]:
        """Determine the optimal model based on routing."""
        if not routing:
            return None

        # Map agent tiers to actual model names
        agent_to_model = {
            AgentTier.FLASH: None,  # Use Gemini Flash for internal decisions only
            AgentTier.HAIKU: "haiku",
            AgentTier.SONNET: "sonnet",
            AgentTier.OPUS: "opus",
            AgentTier.PRO: None,  # Pro is for internal reasoning
        }

        return agent_to_model.get(routing.recommended_agent)

    def _calculate_priority(self, routing: Optional[RoutingDecision]) -> int:
        """Calculate task priority based on routing."""
        if not routing:
            return 5

        # Higher complexity = higher priority (lower number)
        complexity_priority = {
            TaskComplexity.TRIVIAL: 8,
            TaskComplexity.SIMPLE: 6,
            TaskComplexity.MODERATE: 5,
            TaskComplexity.COMPLEX: 3,
            TaskComplexity.RESEARCH: 4,
        }

        return complexity_priority.get(routing.complexity, 5)

    def _extract_tags(self, task: str, domain_context: Optional[Dict]) -> list:
        """Extract tags for task categorization."""
        tags = []

        if domain_context:
            tags.append(domain_context.get("domain", "general"))

        # Add keyword-based tags
        task_lower = task.lower()
        if "bug" in task_lower or "fix" in task_lower:
            tags.append("bugfix")
        if "feature" in task_lower or "implement" in task_lower:
            tags.append("feature")
        if "test" in task_lower:
            tags.append("testing")
        if "refactor" in task_lower:
            tags.append("refactor")

        return tags

    def validate_output(self, task: str, output: str,
                       context: Dict[str, Any] = None) -> ValidationResult:
        """
        Validate agent output using SmartRouter.

        Args:
            task: Original task
            output: Agent output
            context: Additional context

        Returns:
            ValidationResult with quality assessment
        """
        if not self.smart_router:
            # Return default valid result
            return ValidationResult(
                is_valid=True,
                quality_score=0.7,
                issues=[],
                suggestions=[],
                needs_retry=False
            )

        return self.smart_router.validate_response(task, output, context)

    def should_continue(self, task: str, output: str,
                       validation: ValidationResult) -> Tuple[bool, Optional[str]]:
        """
        Determine if task needs continuation.

        Args:
            task: Original task
            output: Current output
            validation: Validation result

        Returns:
            (should_continue, continuation_prompt)
        """
        if not validation.is_valid:
            return True, f"Previous attempt had issues: {', '.join(validation.issues)}. Please retry."

        if validation.needs_retry:
            return True, validation.continuation_prompt

        if validation.quality_score < 0.6:
            return True, "Output quality is below threshold. Please improve the response."

        return False, None

    def create_augmented_prompt(self, context: EnhancedDispatchContext) -> str:
        """
        Create an augmented prompt with routing context.

        Args:
            context: Enhanced dispatch context

        Returns:
            Augmented task prompt
        """
        parts = [context.task]

        # Add domain guidance if available
        if context.domain_context:
            practices = context.domain_context.get("best_practices", [])
            if practices:
                parts.append("\n\nBest practices for this task:")
                for practice in practices[:3]:
                    parts.append(f"- {practice}")

        # Add suggested steps if available
        if context.routing_decision and context.routing_decision.suggested_steps:
            parts.append("\n\nSuggested approach:")
            for i, step in enumerate(context.routing_decision.suggested_steps[:5], 1):
                parts.append(f"{i}. {step}")

        return "\n".join(parts)

    def record_completion(self, context: EnhancedDispatchContext,
                         output: str, success: bool,
                         duration_seconds: float) -> None:
        """
        Record task completion for learning.

        Args:
            context: Dispatch context
            output: Task output
            success: Whether task succeeded
            duration_seconds: Execution duration
        """
        if not self.flow_intelligence:
            return

        # Create or update flow
        try:
            # Simplified recording
            logger.info(f"Task {context.project}: {'Success' if success else 'Failed'} in {duration_seconds:.1f}s")
        except Exception as e:
            logger.warning(f"Failed to record completion: {e}")

    def get_stats(self) -> Dict[str, Any]:
        """Get combined statistics from all components."""
        stats = {
            "smart_router": {},
            "semantic_router": {},
            "flow_intelligence": {}
        }

        if self.smart_router:
            stats["smart_router"] = self.smart_router.get_stats()

        if self.flow_intelligence:
            stats["flow_intelligence"] = self.flow_intelligence.get_stats()

        return stats


# Singleton instance for easy access
_orchestrator_instance = None


def get_orchestrator() -> SmartFlowOrchestrator:
    """Get or create singleton orchestrator instance."""
    global _orchestrator_instance
    if _orchestrator_instance is None:
        _orchestrator_instance = SmartFlowOrchestrator()
    return _orchestrator_instance


def smart_dispatch_prepare(task: str, project: str,
                          context: Dict[str, Any] = None) -> EnhancedDispatchContext:
    """
    Convenience function for smart dispatch preparation.

    Args:
        task: Task description
        project: Target project
        context: Additional context

    Returns:
        EnhancedDispatchContext
    """
    return get_orchestrator().prepare_dispatch(task, project, context)


def smart_validate_output(task: str, output: str,
                         context: Dict[str, Any] = None) -> ValidationResult:
    """
    Convenience function for output validation.

    Args:
        task: Original task
        output: Agent output
        context: Additional context

    Returns:
        ValidationResult
    """
    return get_orchestrator().validate_output(task, output, context)


# CLI for testing
if __name__ == "__main__":
    import sys

    logger.info("=" * 60)
    logger.info("Smart Flow Integration Test")
    logger.info("=" * 60)

    orchestrator = SmartFlowOrchestrator()

    # Test cases
    test_cases = [
        ("Fix the login button styling", "overbits"),
        ("Implement OAuth2 authentication with refresh tokens", "dss"),
        ("Research microservices communication patterns", "admin"),
        ("List all running Docker containers", "admin"),
    ]

    for task, project in test_cases:
        logger.info(f"\n{'='*40}")
        logger.info(f"Task: {task}")
        logger.info(f"Project: {project}")

        context = orchestrator.prepare_dispatch(task, project)

        logger.info(f"\nRouting Decision:")
        if context.routing_decision:
            logger.info(f"  Complexity: {context.routing_decision.complexity.value}")
            logger.info(f"  Agent: {context.routing_decision.recommended_agent.value}")
            logger.info(f"  Confidence: {context.routing_decision.confidence:.2f}")
            logger.info(f"  Steps: {context.routing_decision.suggested_steps[:2]}")

        logger.info(f"\nDomain Context:")
        if context.domain_context:
            logger.info(f"  Domain: {context.domain_context.get('domain')}")
            logger.info(f"  Confidence: {context.domain_context.get('confidence', 0):.2f}")

        logger.info(f"\nModel Override: {context.model_override}")
        logger.info(f"Priority: {context.priority}")
        logger.info(f"Tags: {context.tags}")

        # Test augmented prompt
        augmented = orchestrator.create_augmented_prompt(context)
        logger.info(f"\nAugmented Prompt Preview:")
        logger.info(augmented[:200] + "..." if len(augmented) > 200 else augmented)

    # Show stats
    logger.info(f"\n{'='*60}")
    stats = orchestrator.get_stats()
    logger.info(f"Stats: {json.dumps(stats, indent=2)}")
    logger.info("=" * 60)
