"""
User Node Pattern Examples

This module demonstrates various patterns for using the User node in multi-agent topologies.
"""

import asyncio
import logging
from typing import Dict, Any

from marsys.coordination import Orchestra
from marsys.agents import ReactAgent
from marsys.models import OpenAIModel, AnthropicModel, GoogleModel


# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


# Example 1: Simple Linear Flow
async def example_simple_linear():
    """User -> Coordinator -> Worker pattern"""
    
    logger.info("=== Example 1: Simple Linear Flow ===")
    
    # Create agents
    coordinator = ReactAgent(
        name="Coordinator",
        model=OpenAIModel(model_id="gpt-4-mini"),
        instructions="You coordinate tasks. When you receive a task, analyze it and delegate to Worker."
    )
    
    worker = ReactAgent(
        name="Worker",
        model=OpenAIModel(model_id="gpt-4-mini"),
        instructions="You execute tasks assigned by the Coordinator. Be concise."
    )
    
    # Define topology
    topology = {
        "agents": ["User", "Coordinator", "Worker"],
        "flows": ["User -> Coordinator", "Coordinator -> Worker"]
    }
    
    # Run the workflow
    result = await Orchestra.run(
        task="Calculate the fibonacci sequence up to 10 terms",
        topology=topology
    )
    
    logger.info(f"Result: {result.final_response}")
    logger.info(f"Total steps: {result.total_steps}")
    return result


# Example 2: Bidirectional Communication
async def example_bidirectional():
    """User <-> Assistant pattern for interactive Q&A"""
    
    logger.info("\n=== Example 2: Bidirectional Communication ===")
    
    # Create an interactive assistant
    assistant = ReactAgent(
        name="Assistant",
        model=AnthropicModel(model_id="claude-3-haiku-20240307"),
        instructions="""You are an interactive assistant. You can:
        1. Answer questions directly
        2. Ask for clarification if the question is ambiguous
        3. Provide follow-up information
        Always be helpful and concise."""
    )
    
    # Bidirectional topology
    topology = {
        "agents": ["User", "Assistant"],
        "flows": ["User <-> Assistant"],
        "rules": ["max_turns(User <-> Assistant, 3)"]  # Limit conversation
    }
    
    result = await Orchestra.run(
        task="What's the weather like?",  # Ambiguous question
        topology=topology
    )
    
    logger.info(f"Conversation result: {result.final_response}")
    return result


# Example 3: Parallel Specialist Access
async def example_parallel_specialists():
    """User triggers multiple specialists in parallel"""
    
    logger.info("\n=== Example 3: Parallel Specialist Access ===")
    
    # Create specialist agents
    researcher = ReactAgent(
        name="Researcher",
        model=GoogleModel(model_id="gemini-1.5-flash"),
        instructions="Research and provide factual information about the topic."
    )
    
    analyst = ReactAgent(
        name="Analyst",
        model=OpenAIModel(model_id="gpt-4-mini"),
        instructions="Analyze trends and patterns in the given topic."
    )
    
    summarizer = ReactAgent(
        name="Summarizer",
        model=AnthropicModel(model_id="claude-3-haiku-20240307"),
        instructions="Create concise summaries of complex information."
    )
    
    coordinator = ReactAgent(
        name="Coordinator",
        model=OpenAIModel(model_id="gpt-4"),
        instructions="Combine insights from all specialists into a coherent response."
    )
    
    # Parallel execution topology
    topology = {
        "agents": ["User", "Researcher", "Analyst", "Summarizer", "Coordinator"],
        "flows": [
            "User -> Researcher",      # These three execute
            "User -> Analyst",         # in parallel
            "User -> Summarizer",      # automatically
            "Researcher -> Coordinator",
            "Analyst -> Coordinator",
            "Summarizer -> Coordinator"
        ]
    }
    
    result = await Orchestra.run(
        task="Explain the impact of artificial intelligence on healthcare",
        topology=topology
    )
    
    logger.info(f"Combined analysis: {result.final_response}")
    logger.info(f"Parallel branches created: {len(result.branch_results)}")
    return result


# Example 4: Hub and Spoke with User Control
async def example_hub_and_spoke():
    """User as the hub in a hub-and-spoke pattern"""
    
    logger.info("\n=== Example 4: Hub and Spoke with User Control ===")
    
    # Create specialized agents
    data_fetcher = ReactAgent(
        name="DataFetcher",
        model=OpenAIModel(model_id="gpt-4-mini"),
        instructions="Fetch and retrieve relevant data for analysis."
    )
    
    analyzer = ReactAgent(
        name="Analyzer",
        model=GoogleModel(model_id="gemini-1.5-flash"),
        instructions="Perform statistical analysis on provided data."
    )
    
    reporter = ReactAgent(
        name="Reporter",
        model=AnthropicModel(model_id="claude-3-haiku-20240307"),
        instructions="Generate reports based on analysis results."
    )
    
    # Hub and spoke with User at center
    topology = {
        "agents": ["User", "DataFetcher", "Analyzer", "Reporter"],
        "flows": [
            "User <-> DataFetcher",
            "User <-> Analyzer",
            "User <-> Reporter",
            "DataFetcher -> Analyzer",  # Data flow
            "Analyzer -> Reporter"      # Results flow
        ]
    }
    
    result = await Orchestra.run(
        task="Analyze sales trends for Q4 2024",
        topology=topology
    )
    
    logger.info(f"Final report: {result.final_response}")
    return result


# Example 5: Multi-Stage Pipeline
async def example_pipeline():
    """User initiates a multi-stage processing pipeline"""
    
    logger.info("\n=== Example 5: Multi-Stage Pipeline ===")
    
    # Create pipeline stages
    validator = ReactAgent(
        name="Validator",
        model=OpenAIModel(model_id="gpt-4-mini"),
        instructions="Validate input data and check for errors or inconsistencies."
    )
    
    processor = ReactAgent(
        name="Processor",
        model=GoogleModel(model_id="gemini-1.5-flash"),
        instructions="Process validated data according to business rules."
    )
    
    reviewer = ReactAgent(
        name="Reviewer",
        model=AnthropicModel(model_id="claude-3-haiku-20240307"),
        instructions="Review processed results for quality and accuracy."
    )
    
    publisher = ReactAgent(
        name="Publisher",
        model=OpenAIModel(model_id="gpt-4-mini"),
        instructions="Format and publish the final results."
    )
    
    # Pipeline topology with feedback to User
    topology = {
        "agents": ["User", "Validator", "Processor", "Reviewer", "Publisher"],
        "flows": [
            "User -> Validator",
            "Validator -> Processor",
            "Processor -> Reviewer",
            "Reviewer -> Publisher",
            "Publisher -> User"  # Results return to user
        ]
    }
    
    result = await Orchestra.run(
        task="Process customer order #12345 with items: Widget A (qty: 5), Gadget B (qty: 2)",
        topology=topology
    )
    
    logger.info(f"Pipeline result: {result.final_response}")
    logger.info(f"Pipeline stages: {result.total_steps}")
    return result


# Example 6: Conditional Routing
async def example_conditional_routing():
    """User input determines which specialist to consult"""
    
    logger.info("\n=== Example 6: Conditional Routing ===")
    
    # Create router and specialists
    router = ReactAgent(
        name="Router",
        model=OpenAIModel(model_id="gpt-4-mini"),
        instructions="""You are a smart router. Based on the user's request:
        - For technical questions, route to TechExpert
        - For business questions, route to BusinessExpert  
        - For creative tasks, route to CreativeExpert
        Analyze the request and invoke the appropriate expert."""
    )
    
    tech_expert = ReactAgent(
        name="TechExpert",
        model=GoogleModel(model_id="gemini-1.5-flash"),
        instructions="Provide technical expertise on programming, systems, and engineering topics."
    )
    
    business_expert = ReactAgent(
        name="BusinessExpert",
        model=OpenAIModel(model_id="gpt-4"),
        instructions="Provide business insights, strategy, and financial analysis."
    )
    
    creative_expert = ReactAgent(
        name="CreativeExpert",
        model=AnthropicModel(model_id="claude-3-sonnet-20240229"),
        instructions="Help with creative tasks like writing, design ideas, and artistic concepts."
    )
    
    # Routing topology
    topology = {
        "agents": ["User", "Router", "TechExpert", "BusinessExpert", "CreativeExpert"],
        "flows": [
            "User -> Router",
            "Router -> TechExpert",
            "Router -> BusinessExpert",
            "Router -> CreativeExpert"
        ]
    }
    
    # Test with different types of requests
    tech_result = await Orchestra.run(
        task="How do I implement a binary search tree in Python?",
        topology=topology
    )
    logger.info(f"Tech query result: {tech_result.final_response[:100]}...")
    
    business_result = await Orchestra.run(
        task="What's a good strategy for market penetration?",
        topology=topology
    )
    logger.info(f"Business query result: {business_result.final_response[:100]}...")
    
    return tech_result, business_result


# Example 7: Error Handling Pattern
async def example_error_handling():
    """Demonstration of what happens with reserved names"""
    
    logger.info("\n=== Example 7: Error Handling Demo ===")
    
    try:
        # This will raise AgentConfigurationError
        user_agent = ReactAgent(
            name="User",  # Reserved name!
            model=OpenAIModel(model_id="gpt-4-mini"),
            instructions="This should fail"
        )
    except Exception as e:
        logger.error(f"Expected error: {type(e).__name__}: {e}")
    
    try:
        # This will also fail
        system_agent = ReactAgent(
            name="System",  # Also reserved!
            model=OpenAIModel(model_id="gpt-4-mini"),
            instructions="This should also fail"
        )
    except Exception as e:
        logger.error(f"Expected error: {type(e).__name__}: {e}")
    
    # Valid alternative names
    user_interface = ReactAgent(
        name="UserInterface",  # This is fine
        model=OpenAIModel(model_id="gpt-4-mini"),
        instructions="Handle user interactions"
    )
    logger.info("Successfully created UserInterface agent")


async def main():
    """Run all examples"""
    
    # Note: These examples require API keys to be configured
    # Set your API keys in environment variables or .env file
    
    examples = [
        example_simple_linear,
        example_bidirectional,
        example_parallel_specialists,
        example_hub_and_spoke,
        example_pipeline,
        example_conditional_routing,
        example_error_handling
    ]
    
    for example_func in examples:
        try:
            await example_func()
        except Exception as e:
            logger.error(f"Example {example_func.__name__} failed: {e}")
        
        # Small delay between examples
        await asyncio.sleep(1)


if __name__ == "__main__":
    asyncio.run(main())