"""CLI visualization utilities for dependency graphs and execution display."""

from collections.abc import Callable
from typing import Any

import click
from rich.console import Console
from rich.markdown import Markdown
from rich.tree import Tree

from llm_orc.core.config.ensemble_config import EnsembleConfig


def create_dependency_graph(agents: list[dict[str, Any]]) -> str:
    """Create horizontal dependency graph: A,B,C → D → E,F → G"""
    return create_dependency_graph_with_status(agents, {})


def create_dependency_tree(
    agents: list[dict[str, Any]], agent_statuses: dict[str, str] | None = None
) -> Tree:
    """Create a tree visualization of agent dependencies by execution levels."""
    if agent_statuses is None:
        agent_statuses = {}

    # Group agents by dependency level
    agents_by_level = _group_agents_by_dependency_level(agents)
    tree = Tree("[bold blue]Orchestrating Agent Responses[/bold blue]")

    max_level = max(agents_by_level.keys()) if agents_by_level else 0

    # Create each level as a single line with agents grouped together
    for level in range(max_level + 1):
        if level not in agents_by_level:
            continue

        level_agents = agents_by_level[level]

        # Create agent status strings for this level
        agent_labels = []
        for agent in level_agents:
            agent_name = agent["name"]
            status = agent_statuses.get(agent_name, "pending")

            if status == "running":
                symbol = "[yellow]◐[/yellow]"
                style = "yellow"
            elif status == "completed":
                symbol = "[green]✓[/green]"
                style = "green"
            elif status == "failed":
                symbol = "[red]✗[/red]"
                style = "red"
            elif status == "waiting_input":
                symbol = "[blue]⏸[/blue]"
                style = "blue"
            else:
                symbol = "[dim]○[/dim]"
                style = "dim"

            agent_label = f"{symbol} [{style}]{agent_name}[/{style}]"
            agent_labels.append(agent_label)

        # Join all agents at this level into a single line
        level_line = "  ".join(agent_labels)
        tree.add(level_line)

    return tree


def _group_agents_by_dependency_level(
    agents: list[dict[str, Any]],
) -> dict[int, list[dict[str, Any]]]:
    """Group agents by their dependency level (0 = no dependencies)."""
    agents_by_level: dict[int, list[dict[str, Any]]] = {}

    for agent in agents:
        dependencies = agent.get("depends_on", [])
        level = _calculate_agent_level(agent["name"], dependencies, agents)

        if level not in agents_by_level:
            agents_by_level[level] = []
        agents_by_level[level].append(agent)

    return agents_by_level


_PLAIN_STATUS_SYMBOLS: dict[str, str] = {
    "running": "◐",
    "completed": "✓",
    "failed": "✗",
    "waiting_input": "⏸",
}

_RICH_STATUS_FORMATS: dict[str, str] = {
    "running": "[yellow]◐[/yellow] [yellow]{name}[/yellow]",
    "completed": "[green]✓[/green] [green]{name}[/green]",
    "failed": "[red]✗[/red] [red]{name}[/red]",
    "waiting_input": "[blue]⏸[/blue] [blue]{name}[/blue]",
}


def _build_dependency_graph(
    agents: list[dict[str, Any]],
    agent_statuses: dict[str, str],
    format_agent: Callable[[str, str], str],
) -> str:
    """Build a horizontal dependency graph string using a formatting function."""
    agents_by_level = _group_agents_by_dependency_level(agents)
    if not agents_by_level:
        return ""

    graph_parts = []
    for level in range(max(agents_by_level) + 1):
        level_agents = agents_by_level.get(level, [])
        if not level_agents:
            continue
        displays = [
            format_agent(agent["name"], agent_statuses.get(agent["name"], "pending"))
            for agent in level_agents
        ]
        graph_parts.append(", ".join(displays))

    return " → ".join(graph_parts)


def _create_plain_text_dependency_graph(
    agents: list[dict[str, Any]], agent_statuses: dict[str, str]
) -> str:
    """Create plain text dependency graph without Rich formatting."""

    def fmt(name: str, status: str) -> str:
        symbol = _PLAIN_STATUS_SYMBOLS.get(status, "○")
        return f"{symbol} {name}"

    return _build_dependency_graph(agents, agent_statuses, fmt)


def create_dependency_graph_with_status(
    agents: list[dict[str, Any]], agent_statuses: dict[str, str]
) -> str:
    """Create horizontal dependency graph with status indicators."""

    def fmt(name: str, status: str) -> str:
        template = _RICH_STATUS_FORMATS.get(status, "[dim]○[/dim] [dim]{name}[/dim]")
        return template.format(name=name)

    return _build_dependency_graph(agents, agent_statuses, fmt)


def _calculate_agent_level(
    agent_name: str, dependencies: list[str], all_agents: list[dict[str, Any]]
) -> int:
    """Calculate the dependency level of an agent (0 = no dependencies)."""
    if not dependencies:
        return 0

    # Find the maximum level of all dependencies
    max_dep_level = 0
    for dep_name in dependencies:
        # Find the dependency agent
        dep_agent = next((a for a in all_agents if a["name"] == dep_name), None)
        if dep_agent:
            dep_dependencies = dep_agent.get("depends_on", [])
            dep_level = _calculate_agent_level(dep_name, dep_dependencies, all_agents)
            max_dep_level = max(max_dep_level, dep_level)

    return max_dep_level + 1


def _process_agent_results(
    results: dict[str, Any], metadata: dict[str, Any]
) -> list[str]:
    """Process agent results and generate markdown content.

    Args:
        results: Dictionary of agent results
        metadata: Metadata dictionary containing usage information

    Returns:
        List of markdown content strings for agent results
    """
    markdown_content = []

    # Get agent usage data for model information
    agents_usage = metadata.get("usage", {}).get("agents", {})

    for agent_name, result in results.items():
        # Get model information for this agent
        agent_usage = agents_usage.get(agent_name, {})
        model = agent_usage.get("model", "")
        model_profile = agent_usage.get("model_profile", "")

        # Create model display string
        model_display = ""
        if model_profile and model:
            model_display = f" ({model_profile} → {model})"
        elif model:
            model_display = f" ({model})"

        if result.get("status") == "success":
            markdown_content.append(f"## {agent_name}{model_display}\n")
            # Format the response as a code block if it looks like code,
            # otherwise as regular text (let Rich handle wrapping)
            response = result["response"]
            # Convert response to string if it's a list (e.g., fan-out gathered results)
            if isinstance(response, list):
                import json

                response = json.dumps(response, indent=2)
            code_keywords = ["def ", "class ", "```", "import ", "function"]
            if any(keyword in response.lower() for keyword in code_keywords):
                markdown_content.append(f"```\n{response}\n```\n")
            else:
                markdown_content.append(f"{response}\n")
        else:
            markdown_content.append(f"## ❌ {agent_name}{model_display}\n")
            error_msg = result.get("error", "Unknown error")
            markdown_content.append(f"**Error:** {error_msg}\n")

    return markdown_content


def _format_performance_metrics(metadata: dict[str, Any]) -> list[str]:
    """Format performance metrics into markdown content.

    Args:
        metadata: Metadata dictionary containing usage information

    Returns:
        List of markdown content strings for performance metrics
    """
    markdown_content: list[str] = []

    if "usage" not in metadata:
        return markdown_content

    usage = metadata["usage"]
    totals = usage.get("totals", {})

    markdown_content.append("## Performance Metrics\n")
    markdown_content.append(f"- **Duration:** {metadata['duration']}\n")

    total_tokens = totals.get("total_tokens", 0)
    total_cost = totals.get("total_cost_usd", 0.0)
    markdown_content.append(f"- **Total tokens:** {total_tokens:,}\n")
    markdown_content.append(f"- **Total cost:** ${total_cost:.4f}\n")
    markdown_content.append(f"- **Agents:** {totals.get('agents_count', 0)}\n")

    # Show adaptive resource management statistics if available
    adaptive_stats = metadata.get("adaptive_resource_management")
    if adaptive_stats:
        markdown_content.extend(_format_adaptive_resource_metrics(adaptive_stats))

    # Show per-agent usage
    agents_usage = usage.get("agents", {})
    if agents_usage:
        markdown_content.append("\n### Per-Agent Usage\n")
        for agent_name, agent_usage in agents_usage.items():
            tokens = agent_usage.get("total_tokens", 0)
            cost = agent_usage.get("cost_usd", 0.0)
            duration = agent_usage.get("duration_ms", 0)
            model = agent_usage.get("model", "unknown")
            model_profile = agent_usage.get("model_profile", "unknown")

            # Show both model profile and actual model to detect fallbacks
            model_display = (
                f"{model_profile} → {model}" if model_profile != "unknown" else model
            )

            markdown_content.append(
                f"- **{agent_name}** ({model_display}): {tokens:,} tokens, "
                f"${cost:.4f}, {duration}ms\n"
            )

    return markdown_content


def display_results(
    results: dict[str, Any], metadata: dict[str, Any], detailed: bool = False
) -> None:
    """Display results in a formatted way using Rich markdown rendering."""
    console = Console(soft_wrap=True, width=None, force_terminal=True)

    if detailed:
        # Build markdown content using comprehensive JSON-first architecture
        from .json_renderer import (
            render_comprehensive_markdown,
            transform_to_execution_json,
        )

        # Get usage data from metadata (extract from performance metrics helper)
        usage_data = metadata.get("usage", {})

        # Transform to structured JSON (single source of truth)
        execution_json = transform_to_execution_json(results, usage_data, metadata)

        # Render EVERYTHING from structured JSON (single source of truth)
        markdown_content = ["# Results\n"]

        # Use comprehensive JSON-first renderer for ALL content including agents
        comprehensive_markdown = render_comprehensive_markdown(execution_json)
        if comprehensive_markdown.strip():
            markdown_content.append(comprehensive_markdown)

        # Render the markdown - Rich will handle soft wrapping
        markdown_text = "".join(markdown_content)
        markdown_obj = Markdown(markdown_text)
        console.print(markdown_obj, overflow="ellipsis", crop=True, no_wrap=False)
    else:
        # Simplified output: just show final synthesis/result
        display_simplified_results(results, metadata)


def _display_plain_text_dependency_graph(
    agents: list[dict[str, Any]], results: dict[str, Any]
) -> None:
    """Display dependency graph for plain text output."""
    # Create agent status based on results (completed/failed)
    agent_statuses = {}
    for agent in agents:
        agent_name = agent["name"]
        if agent_name in results:
            status = results[agent_name].get("status", "pending")
            agent_statuses[agent_name] = (
                "completed" if status == "success" else "failed"
            )
        else:
            agent_statuses[agent_name] = "pending"

    # Show dependency graph (plain text version without Rich formatting)
    dependency_graph = _create_plain_text_dependency_graph(agents, agent_statuses)
    click.echo("Dependency Graph:")
    click.echo(dependency_graph)
    click.echo()


def _display_detailed_plain_text(
    results: dict[str, Any], metadata: dict[str, Any]
) -> None:
    """Display detailed plain text results using JSON-first architecture."""
    click.echo("Results")
    click.echo("=======")
    click.echo()

    # Use JSON-first transformation for ALL content (single source of truth)
    from .json_renderer import render_comprehensive_text, transform_to_execution_json

    usage = metadata.get("usage", {})
    execution_json = transform_to_execution_json(results, usage, metadata)

    # Render EVERYTHING from structured JSON
    comprehensive_text = render_comprehensive_text(execution_json)
    if comprehensive_text.strip():
        click.echo(comprehensive_text)

    # Show basic performance summary
    totals = usage.get("totals", {})
    if totals:
        click.echo()
        click.echo("Performance Summary")
        click.echo("==================")
        if "duration" in metadata:
            click.echo(f"Duration: {metadata['duration']}")
        click.echo(f"Total tokens: {totals.get('total_tokens', 0):,}")
        click.echo(f"Total cost: ${totals.get('total_cost_usd', 0.0):.4f}")
        click.echo(f"Agents: {totals.get('agents_count', 0)}")


def _display_simplified_plain_text(
    results: dict[str, Any], metadata: dict[str, Any]
) -> None:
    """Display simplified plain text results."""
    final_agent = find_final_agent(results)

    if final_agent and results[final_agent].get("status") == "success":
        response = results[final_agent]["response"]
        click.echo(response)
    else:
        # Fallback: show last successful agent
        successful_agents = [
            name
            for name, result in results.items()
            if result.get("status") == "success"
        ]
        if successful_agents:
            last_agent = successful_agents[-1]
            response = results[last_agent]["response"]
            click.echo(f"Result from {last_agent}:")
            click.echo(response)
        else:
            click.echo("❌ No successful results found")

    # Show minimal performance summary
    if "usage" in metadata:
        totals = metadata["usage"].get("totals", {})
        agents_count = totals.get("agents_count", 0)
        duration = metadata.get("duration", "unknown")
        click.echo()
        click.echo(f"⚡ {agents_count} agents completed in {duration}")
        click.echo("Use --detailed flag for full results and metrics")


def display_plain_text_results(
    results: dict[str, Any],
    metadata: dict[str, Any],
    detailed: bool = False,
    agents: list[dict[str, Any]] | None = None,
) -> None:
    """Display results in plain text format without Rich formatting."""
    # Show dependency graph if agents provided
    if agents:
        _display_plain_text_dependency_graph(agents, results)

    if detailed:
        _display_detailed_plain_text(results, metadata)
    else:
        _display_simplified_plain_text(results, metadata)


def _format_response_markdown(response: Any) -> str:
    """Format a response for markdown display, handling lists and code detection."""
    import json

    # Convert list responses (e.g., fan-out gathered results) to string
    if isinstance(response, list):
        response = json.dumps(response, indent=2)

    # Format as code block if it looks like code
    code_keywords = ["def ", "class ", "```", "import ", "function"]
    if any(keyword in response.lower() for keyword in code_keywords):
        return f"```\n{response}\n```\n"
    return f"{response}\n"


def display_simplified_results(
    results: dict[str, Any], metadata: dict[str, Any]
) -> None:
    """Display simplified results showing only the final output using markdown."""
    console = Console(soft_wrap=True, width=None, force_terminal=True)

    # Find the final agent (the one with no dependents)
    final_agent = find_final_agent(results)

    markdown_content = []

    if final_agent and results[final_agent].get("status") == "success":
        response = results[final_agent]["response"]
        markdown_content.append("## Result\n\n")
        markdown_content.append(_format_response_markdown(response))
    else:
        # Fallback: show last successful agent
        successful_agents = [
            name
            for name, result in results.items()
            if result.get("status") == "success"
        ]
        if successful_agents:
            last_agent = successful_agents[-1]
            response = results[last_agent]["response"]
            markdown_content.append(f"## Result from {last_agent}\n")
            markdown_content.append(_format_response_markdown(response))
        else:
            markdown_content.append("**❌ No successful results found**\n")

    # Show minimal performance summary
    if "usage" in metadata:
        totals = metadata["usage"].get("totals", {})
        agents_count = totals.get("agents_count", 0)
        duration = metadata.get("duration", "unknown")
        summary = f"\n⚡ **{agents_count} agents completed in {duration}**\n"
        markdown_content.append(summary)
        markdown_content.append("*Use --detailed flag for full results and metrics*\n")

    # Render the markdown
    if markdown_content:
        markdown_text = "".join(markdown_content)
        console.print(
            Markdown(markdown_text), overflow="ellipsis", crop=True, no_wrap=False
        )


def _create_structured_dependency_info(
    agents: list[dict[str, Any]], results: dict[str, Any] | None = None
) -> dict[str, Any]:
    """Create structured dependency information for JSON output."""
    # Group agents by dependency level
    agents_by_level = _group_agents_by_dependency_level(agents)

    # Create agent status if results provided
    agent_statuses = _create_agent_statuses(agents, results) if results else {}

    # Build structured dependency info
    dependency_levels = _build_dependency_levels(
        agents_by_level, agent_statuses, results
    )

    return {
        "dependency_levels": dependency_levels,
        "dependency_graph": (
            _create_plain_text_dependency_graph(agents, agent_statuses)
            if results
            else create_dependency_graph(agents)
        ),
    }


def _create_agent_statuses(
    agents: list[dict[str, Any]], results: dict[str, Any]
) -> dict[str, str]:
    """Create agent status dictionary from results."""
    agent_statuses = {}
    for agent in agents:
        agent_name = agent["name"]
        if agent_name in results:
            status = results[agent_name].get("status", "pending")
            agent_statuses[agent_name] = (
                "completed" if status == "success" else "failed"
            )
        else:
            agent_statuses[agent_name] = "pending"
    return agent_statuses


def _build_dependency_levels(
    agents_by_level: dict[int, list[dict[str, Any]]],
    agent_statuses: dict[str, str],
    results: dict[str, Any] | None,
) -> list[dict[str, Any]]:
    """Build dependency levels structure."""
    dependency_levels = []
    for level in sorted(agents_by_level.keys()):
        level_agents = []
        for agent in agents_by_level[level]:
            agent_info = {
                "name": agent["name"],
                "dependencies": agent.get("depends_on", []),
            }
            if results and agent["name"] in agent_statuses:
                agent_info["status"] = agent_statuses[agent["name"]]
            level_agents.append(agent_info)

        dependency_levels.append({"level": level, "agents": level_agents})
    return dependency_levels


def _format_adaptive_resource_metrics(adaptive_stats: dict[str, Any]) -> list[str]:
    """Format adaptive resource management metrics into markdown content.

    Args:
        adaptive_stats: Adaptive resource management statistics

    Returns:
        List of markdown content strings for adaptive resource metrics
    """
    markdown_content: list[str] = []
    management_type = adaptive_stats.get("management_type", "unknown")
    adaptive_used = adaptive_stats.get("adaptive_used", False)
    concurrency_decisions = adaptive_stats.get("concurrency_decisions", [])

    markdown_content.append("\n### Resource Management\n")

    if adaptive_used and concurrency_decisions:
        markdown_content.extend(
            _format_adaptive_with_decisions(management_type, concurrency_decisions)
        )
    elif concurrency_decisions:
        markdown_content.extend(
            _format_static_with_decisions(management_type, concurrency_decisions)
        )
    elif adaptive_used:
        markdown_content.extend(
            _format_adaptive_no_decisions(management_type, adaptive_stats)
        )
    else:
        # Extract concurrency limit from decisions
        concurrency_limit = 1  # Default fallback
        if concurrency_decisions:
            concurrency_limit = concurrency_decisions[0].get("configured_limit", 1)
        markdown_content.extend(
            _format_static_no_decisions(management_type, concurrency_limit)
        )

    # Add per-phase metrics if available
    phase_metrics = adaptive_stats.get("phase_metrics", [])
    if phase_metrics:
        markdown_content.extend(_format_per_phase_metrics(phase_metrics))

    return markdown_content


def _format_per_phase_metrics(phase_metrics: list[dict[str, Any]]) -> list[str]:
    """Format per-phase monitoring metrics."""
    content = ["\n#### Per-Phase Performance\n"]

    for phase_data in phase_metrics:
        phase_index = phase_data.get("phase_index", "Unknown")
        agent_count = phase_data.get("agent_count", 0)
        agent_names = phase_data.get("agent_names", [])
        sample_count = phase_data.get("sample_count", 0)

        # Get resource usage metrics
        peak_cpu = phase_data.get("peak_cpu", 0.0)
        avg_cpu = phase_data.get("avg_cpu", 0.0)
        peak_memory = phase_data.get("peak_memory", 0.0)
        avg_memory = phase_data.get("avg_memory", 0.0)

        content.append(f"**Phase {phase_index}** ({agent_count} agents)\n")
        content.append(f"- **Agents:** {', '.join(agent_names)}\n")

        # Show duration if available
        duration = phase_data.get("duration_seconds")
        if duration is not None:
            content.append(f"- **Duration:** {duration:.2f} seconds\n")

        if sample_count > 0:
            content.append(
                f"- **Resource usage:** CPU {avg_cpu:.1f}% (peak {peak_cpu:.1f}%), "
                f"Memory {avg_memory:.1f}% (peak {peak_memory:.1f}%)\n"
            )
            content.append(f"- **Monitoring:** {sample_count} samples collected\n")
        else:
            # Show final resource snapshot if available
            final_cpu = phase_data.get("final_cpu_percent")
            final_memory = phase_data.get("final_memory_percent")
            if final_cpu is not None and final_memory is not None:
                content.append(
                    f"- **Resource usage:** CPU {final_cpu:.1f}%, "
                    f"Memory {final_memory:.1f}%\n"
                )
            else:
                content.append("- **Resource usage:** No monitoring data available\n")

        # Show raw samples if available (first few for debugging)
        raw_cpu = phase_data.get("raw_cpu_samples", [])
        if raw_cpu:
            sample_preview = raw_cpu[:3]  # First 3 samples
            content.append(f"- **Sample data:** CPU: {sample_preview}%...\n")

        content.append("\n")

    return content


def _format_adaptive_with_decisions(
    management_type: str, concurrency_decisions: list[dict[str, Any]]
) -> list[str]:
    """Format adaptive resource metrics with concurrency decisions."""
    content = [
        f"- **Type:** {management_type} (adaptive limits based on system resources)\n"
    ]

    final_decision = concurrency_decisions[-1]

    if "adaptive_limit" in final_decision:
        content.extend(_format_adaptive_decision_details(final_decision))
        if len(concurrency_decisions) > 1:
            count = len(concurrency_decisions)
            content.append(
                f"- **Concurrency adjustments:** {count} "
                "decisions made during execution\n"
            )
    else:
        content.append(
            "- **Adaptive resource management enabled** "
            "but no detailed metrics available\n"
        )

    return content


def _format_adaptive_decision_details(final_decision: dict[str, Any]) -> list[str]:
    """Format detailed adaptive decision metrics."""
    adaptive_limit = final_decision.get("adaptive_limit", "unknown")
    cpu_percent = final_decision.get("cpu_percent", 0.0)
    memory_percent = final_decision.get("memory_percent", 0.0)
    circuit_state = final_decision.get("circuit_breaker_state", "unknown")
    base_limit = final_decision.get("base_limit", "unknown")

    return [
        f"- **⚡ Adaptive limit calculated:** {adaptive_limit} "
        f"(CPU: {cpu_percent:.1f}%, Memory: {memory_percent:.1f}%, "
        f"Circuit: {circuit_state})\n",
        f"- **Base limit:** {base_limit}\n",
    ]


def _format_static_with_decisions(
    management_type: str, concurrency_decisions: list[dict[str, Any]]
) -> list[str]:
    """Format static resource metrics with concurrency decisions."""
    content = [f"- **Type:** {management_type} (fixed concurrency limits)\n"]
    final_decision = concurrency_decisions[-1]

    if "static_limit" in final_decision:
        static_limit = final_decision.get("static_limit", "unknown")
        agent_count = final_decision.get("agent_count", "unknown")
        content.append(
            f"- **📊 Static limit applied:** {static_limit} "
            f"concurrent agents (for {agent_count} total agents)\n"
        )

    return content


def _format_adaptive_no_decisions(
    management_type: str, adaptive_stats: dict[str, Any]
) -> list[str]:
    """Format adaptive metrics when no concurrency decisions were needed."""
    content = [
        f"- **Type:** {management_type} (adaptive limits based on system resources)\n",
        "- **User-configured limits used:** No adaptive calculations needed\n",
    ]

    execution_metrics = adaptive_stats.get("execution_metrics", {})
    if execution_metrics:
        content.extend(_format_execution_metrics(execution_metrics, adaptive_stats))
    else:
        content.extend(_format_execution_summary({}))

    return content


def _format_execution_metrics(
    execution_metrics: dict[str, Any], adaptive_stats: dict[str, Any]
) -> list[str]:
    """Format detailed execution metrics for research analysis."""
    content = []
    peak_cpu = execution_metrics.get("peak_cpu", 0.0)
    avg_cpu = execution_metrics.get("avg_cpu", 0.0)
    peak_memory = execution_metrics.get("peak_memory", 0.0)
    avg_memory = execution_metrics.get("avg_memory", 0.0)
    sample_count = execution_metrics.get("sample_count", 0)

    # Get circuit state from resource metrics if available
    circuit_state = "unknown"
    resource_metrics = adaptive_stats.get("resource_metrics", [])
    if resource_metrics:
        circuit_state = resource_metrics[-1].get("circuit_breaker_state", "unknown")

    content.extend(
        [
            f"- **Peak resource usage during execution:** "
            f"CPU {peak_cpu:.1f}%, Memory {peak_memory:.1f}%\n",
            f"- **Average resource usage during execution:** "
            f"CPU {avg_cpu:.1f}%, Memory {avg_memory:.1f}%\n",
            f"- **Monitoring details:** {sample_count} samples collected, "
            f"Circuit: {circuit_state}\n",
        ]
    )

    # Show raw samples for research purposes
    raw_cpu_samples = execution_metrics.get("raw_cpu_samples")
    raw_memory_samples = execution_metrics.get("raw_memory_samples")
    if raw_cpu_samples and raw_memory_samples:
        cpu_str = ", ".join(f"{s:.1f}" for s in raw_cpu_samples)
        memory_str = ", ".join(
            f"{s:.1f}" for s in raw_memory_samples[: len(raw_cpu_samples)]
        )
        content.append(
            f"- **Sample data (first 10):** CPU: [{cpu_str}]%, "
            f"Memory: [{memory_str}]%\n"
        )

    if sample_count == 0:
        content.append(
            "- **Note:** No monitoring samples collected - "
            "execution may have been too fast\n"
        )

    return content


def _format_execution_summary(execution_metrics: dict[str, Any]) -> list[str]:
    """Format execution metrics summary for markdown display."""
    if not execution_metrics:
        return ["- **No monitoring data collected**\n"]

    peak_cpu = execution_metrics.get("peak_cpu", 0.0)
    avg_cpu = execution_metrics.get("avg_cpu", 0.0)
    peak_memory = execution_metrics.get("peak_memory", 0.0)
    avg_memory = execution_metrics.get("avg_memory", 0.0)
    sample_count = execution_metrics.get("sample_count", 0)

    return [
        f"- **Peak usage:** CPU {peak_cpu:.1f}%, Memory {peak_memory:.1f}%\n",
        f"- **Average usage:** CPU {avg_cpu:.1f}%, Memory {avg_memory:.1f}%\n",
        f"- **Monitoring:** {sample_count} samples collected\n",
    ]


def _format_static_no_decisions(
    management_type: str, concurrency_limit: int
) -> list[str]:
    """Format static management metrics when no decisions were recorded."""
    return [
        f"- **Type:** {management_type} (fixed concurrency limits)\n",
        f"- **Max concurrency limit used: {concurrency_limit}**\n",
    ]


def find_final_agent(results: dict[str, Any]) -> str | None:
    """Find the final agent in the dependency chain (the one with no dependents)."""
    # For now, use a simple heuristic: the agent with the highest token count
    # is likely the final agent (since it got input from all previous agents)
    final_agent = None

    for agent_name in results.keys():
        # This is a simple heuristic - in practice we'd want to track dependencies
        # But for now, we can assume the last successful agent is often the final one
        if results[agent_name].get("status") == "success":
            final_agent = agent_name

    return final_agent


def _update_agent_progress_status(
    agents: list[dict[str, Any]],
    completed_agents: int,
    total_agents: int,
    agent_statuses: dict[str, str],
) -> None:
    """Update agent progress statuses based on completion count.

    Args:
        agents: List of agent configurations
        completed_agents: Number of completed agents
        total_agents: Total number of agents
        agent_statuses: Dictionary to update with agent statuses
    """
    # Mark first N agents as completed, rest as pending
    for i, agent in enumerate(agents):
        if i < completed_agents:
            agent_statuses[agent["name"]] = "completed"
        elif i == completed_agents and completed_agents < total_agents:
            agent_statuses[agent["name"]] = "running"
        else:
            agent_statuses[agent["name"]] = "pending"


def _update_agent_status_by_names(
    agents: list[dict[str, Any]],
    started_agent_names: list[str],
    completed_agent_names: list[str],
    agent_statuses: dict[str, str],
) -> None:
    """Update agent statuses based on specific agent names that have started/completed.

    Args:
        agents: List of agent configurations
        started_agent_names: Names of agents that have started
        completed_agent_names: Names of agents that have completed
        agent_statuses: Dictionary to update with agent statuses
    """
    # Convert to sets for faster lookup
    started_set = set(started_agent_names)
    completed_set = set(completed_agent_names)

    for agent in agents:
        agent_name = agent["name"]
        if agent_name in completed_set:
            agent_statuses[agent_name] = "completed"
        elif agent_name in started_set:
            agent_statuses[agent_name] = "running"
        else:
            agent_statuses[agent_name] = "pending"


def _process_execution_completed_event(
    console: Console,
    status: Any,
    agents: list[dict[str, Any]],
    event_data: dict[str, Any],
    output_format: str,
    detailed: bool,
) -> bool:
    """Process execution completed event and display final results.

    Args:
        console: Rich console instance
        status: Rich status object
        agents: List of agent configurations
        event_data: Event data containing results and metadata
        output_format: Output format (text/json)
        detailed: Whether to show detailed output

    Returns:
        bool: True to indicate loop should break
    """
    # Stop the status spinner and show final results
    status.stop()

    # Final update with all completed
    final_statuses = {agent["name"]: "completed" for agent in agents}
    final_tree = create_dependency_tree(agents, final_statuses)
    console.print(final_tree)
    console.print(f"Completed in {event_data['duration']:.2f}s")

    # Always display results for Rich interface (output_format is None or "rich")
    # The text/JSON outputs are handled separately in _run_text_json_execution
    display_results(event_data["results"], event_data["metadata"], detailed)

    return True


def _handle_fallback_started_event(
    console: Console, event_data: dict[str, Any]
) -> None:
    """Handle agent_fallback_started event display."""
    agent_name = event_data["agent_name"]
    failure_type = event_data.get("failure_type", "unknown")
    error_msg = event_data["original_error"]
    original_profile = event_data.get("original_model_profile", "unknown")
    fallback_model = event_data.get("fallback_model_name", "unknown")

    # Enhanced display with failure type
    if failure_type == "oauth_error":
        failure_emoji = "🔐"
    elif failure_type == "authentication_error":
        failure_emoji = "🔑"
    else:
        failure_emoji = "⚠️"

    console.print(
        f"{failure_emoji} Model profile '{original_profile}' "
        f"failed for agent '{agent_name}' ({failure_type}): {error_msg}"
    )
    console.print(
        f"🔄 Using fallback model '{fallback_model}' for agent '{agent_name}'..."
    )
    console.print("─" * 50)


def _handle_fallback_completed_event(
    console: Console, event_data: dict[str, Any]
) -> None:
    """Handle agent_fallback_completed event display."""
    agent_name = event_data["agent_name"]
    fallback_model = event_data["fallback_model_name"]

    # Use print() to bypass Rich buffering and show immediately
    print(
        f"✅ SUCCESS: Fallback model '{fallback_model}' succeeded for "
        f"agent '{agent_name}'"
    )


def _handle_fallback_failed_event(console: Console, event_data: dict[str, Any]) -> None:
    """Handle agent_fallback_failed event display."""
    agent_name = event_data["agent_name"]
    failure_type = event_data.get("failure_type", "unknown")
    fallback_error = event_data["fallback_error"]
    fallback_model = event_data.get("fallback_model_name", "unknown")

    # Use print() to bypass Rich buffering and show immediately
    print(
        f"❌ FAILED: Fallback model '{fallback_model}' also failed for "
        f"agent '{agent_name}' ({failure_type}): {fallback_error}"
    )


def _handle_text_fallback_started(event_data: dict[str, Any]) -> None:
    """Handle agent_fallback_started event for text output."""
    agent_name = event_data["agent_name"]
    failure_type = event_data.get("failure_type", "unknown")
    error_msg = event_data["original_error"]
    original_profile = event_data.get("original_model_profile", "unknown")
    fallback_model = event_data.get("fallback_model_name", "unknown")

    click.echo(
        f"WARNING: Model profile '{original_profile}' failed for "
        f"agent '{agent_name}' ({failure_type}): {error_msg}"
    )
    click.echo(f"Using fallback model '{fallback_model}' for agent '{agent_name}'...")
    click.echo("─" * 50)


def _handle_text_fallback_completed(event_data: dict[str, Any]) -> None:
    """Handle agent_fallback_completed event for text output."""
    agent_name = event_data["agent_name"]
    fallback_model = event_data["fallback_model_name"]

    click.echo(
        f"SUCCESS: Fallback model '{fallback_model}' succeeded for agent '{agent_name}'"
    )


def _handle_progress_events(
    event_type: str,
    event: dict[str, Any],
    agent_statuses: dict[str, str],
    ensemble_config: EnsembleConfig,
    status: Any,
) -> None:
    """Handle progress-related events that update the dependency tree."""
    if event_type == "agent_progress":
        # Extract detailed agent status from progress data
        started_agent_names = event["data"].get("started_agent_names", [])
        completed_agent_names = event["data"].get("completed_agent_names", [])

        # Update agent statuses based on actual agent states
        _update_agent_status_by_names(
            ensemble_config.agents,
            started_agent_names,
            completed_agent_names,
            agent_statuses,
        )

    # All progress events update the dependency tree
    current_tree = create_dependency_tree(ensemble_config.agents, agent_statuses)
    status.update(current_tree)


def _handle_agent_lifecycle_events(
    event_type: str,
    event: dict[str, Any],
    agent_statuses: dict[str, str],
    ensemble_config: EnsembleConfig,
    status: Any,
) -> None:
    """Handle agent lifecycle events (started, completed)."""
    event_data = event["data"]
    agent_name = event_data["agent_name"]

    if event_type == "agent_started":
        agent_statuses[agent_name] = "running"
    elif event_type == "agent_completed":
        agent_statuses[agent_name] = "completed"

    # Update status display with current dependency tree
    current_tree = create_dependency_tree(ensemble_config.agents, agent_statuses)
    status.update(current_tree)


def _handle_fallback_events(
    event_type: str,
    event: dict[str, Any],
    agent_statuses: dict[str, str],
    ensemble_config: EnsembleConfig,
    status: Any,
    console: Console,
) -> None:
    """Handle fallback-related events."""
    event_data = event["data"]
    agent_name = event_data["agent_name"]

    if event_type == "agent_fallback_started":
        agent_statuses[agent_name] = "running"
        _handle_fallback_started_event(console, event_data)
    elif event_type == "agent_fallback_completed":
        agent_statuses[agent_name] = "completed"
    elif event_type == "agent_fallback_failed":
        agent_statuses[agent_name] = "failed"
        _handle_fallback_failed_event(console, event_data)

    # Update status display with current dependency tree
    current_tree = create_dependency_tree(ensemble_config.agents, agent_statuses)
    status.update(current_tree)


def _handle_user_input_events(
    event_type: str,
    event: dict[str, Any],
    agent_statuses: dict[str, str],
    ensemble_config: EnsembleConfig,
    status: Any,
    console: Console,
) -> None:
    """Handle user input events."""
    event_data = event["data"]
    agent_name = event_data["agent_name"]

    if event_type == "user_input_required":
        # Update agent status to waiting_input
        agent_statuses[agent_name] = "waiting_input"

        # Stop the status spinner and clear the terminal
        status.stop()
        console.clear()

        # Update status display with current tree showing waiting status
        current_tree = create_dependency_tree(ensemble_config.agents, agent_statuses)
        console.print(current_tree)

    elif event_type == "user_input_completed":
        # Update agent status back to running
        agent_statuses[agent_name] = "running"

        # Restart the status display with updated tree
        current_tree = create_dependency_tree(ensemble_config.agents, agent_statuses)
        status.start()
        status.update(current_tree)


def _handle_streaming_event(
    event_type: str,
    event: dict[str, Any],
    agent_statuses: dict[str, str],
    ensemble_config: EnsembleConfig,
    status: Any,
    console: Console,
    output_format: str = "rich",
    detailed: bool = False,
) -> bool:
    """Handle a single streaming event and update status display.

    Returns True if execution should continue, False if it should break.
    """
    if event_type in ["agent_progress", "execution_started", "execution_progress"]:
        _handle_progress_events(
            event_type, event, agent_statuses, ensemble_config, status
        )

    elif event_type in ["agent_started", "agent_completed"]:
        _handle_agent_lifecycle_events(
            event_type, event, agent_statuses, ensemble_config, status
        )

    elif event_type in [
        "agent_fallback_started",
        "agent_fallback_completed",
        "agent_fallback_failed",
    ]:
        _handle_fallback_events(
            event_type, event, agent_statuses, ensemble_config, status, console
        )

    elif event_type == "execution_completed":
        # Process execution completed event using helper method
        return _process_execution_completed_event(
            console,
            status,
            ensemble_config.agents,
            event["data"],
            output_format,
            detailed,
        )

    elif event_type in ["user_input_required", "user_input_completed"]:
        _handle_user_input_events(
            event_type, event, agent_statuses, ensemble_config, status, console
        )

    return True


def _handle_text_fallback_failed(event_data: dict[str, Any]) -> None:
    """Handle agent_fallback_failed event for text output."""
    agent_name = event_data["agent_name"]
    failure_type = event_data.get("failure_type", "unknown")
    fallback_error = event_data["fallback_error"]
    fallback_model = event_data.get("fallback_model_name", "unknown")

    click.echo(
        f"ERROR: Fallback model '{fallback_model}' also failed for "
        f"agent '{agent_name}' ({failure_type}): {fallback_error}"
    )


async def _run_text_json_execution(
    executor: Any,
    ensemble_config: EnsembleConfig,
    input_data: str,
    output_format: str,
    detailed: bool,
) -> None:
    """Run execution with text or JSON output (no Rich interface)."""
    if output_format == "json":
        await _run_json_execution(executor, ensemble_config, input_data)
    else:
        await _run_text_execution(executor, ensemble_config, input_data, detailed)


async def _run_json_execution(
    executor: Any,
    ensemble_config: EnsembleConfig,
    input_data: str,
) -> None:
    """Handle JSON output execution."""
    import json

    # For JSON output, collect all meaningful events and output as single JSON
    collected_events: list[dict[str, Any]] = []
    meaningful_events = {
        "execution_started",
        "execution_completed",
        "agent_started",
        "agent_completed",
        "agent_fallback_started",
        "agent_fallback_completed",
        "agent_fallback_failed",
        "phase_started",
        "phase_completed",
    }

    final_result = None
    async for event in executor.execute_streaming(ensemble_config, input_data):
        event_type = event["type"]

        if event_type in meaningful_events:
            collected_events.append(event)

        # Store final result for consolidated output
        if event_type == "execution_completed":
            final_result = event["data"]

    # Add structured dependency information
    dependency_info = _create_structured_dependency_info(
        ensemble_config.agents, final_result["results"] if final_result else None
    )

    # Output consolidated JSON structure
    output_data = {
        "events": collected_events,
        "result": final_result,
        "dependency_info": dependency_info,
    }
    click.echo(json.dumps(output_data, indent=2))


async def _run_text_execution(
    executor: Any,
    ensemble_config: EnsembleConfig,
    input_data: str,
    detailed: bool,
) -> None:
    """Handle text output execution."""
    # Handle text output - stream events as they come
    async for event in executor.execute_streaming(ensemble_config, input_data):
        event_type = event["type"]
        if event_type == "agent_fallback_started":
            _handle_text_fallback_started(event["data"])
        elif event_type == "agent_fallback_completed":
            _handle_text_fallback_completed(event["data"])
        elif event_type == "agent_fallback_failed":
            _handle_text_fallback_failed(event["data"])
        elif event_type == "execution_completed":
            # Show final results for text output using plain text formatting
            display_plain_text_results(
                event["data"]["results"],
                event["data"]["metadata"],
                detailed,
                ensemble_config.agents,
            )


async def run_streaming_execution(
    executor: Any,
    ensemble_config: EnsembleConfig,
    input_data: str,
    output_format: str,
    detailed: bool,
) -> None:
    """Run streaming execution with Rich status display."""
    console = Console(soft_wrap=True, width=None, force_terminal=True)
    agent_statuses: dict[str, str] = {}

    # Use Rich interface by default (None), but simple processing for explicit text/json
    if output_format in ["json", "text"]:
        # Direct processing without Rich status for JSON/text output
        await _run_text_json_execution(
            executor, ensemble_config, input_data, output_format, detailed
        )
    else:
        # Rich interface for default output (None = streaming)
        # Initialize with dependency tree in status display
        initial_tree = create_dependency_tree(ensemble_config.agents, agent_statuses)

        with console.status(initial_tree, spinner="dots") as status:
            # Create progress controller for synchronous user input handling
            from llm_orc.cli_modules.utils.rich_progress_controller import (
                RichProgressController,
            )

            progress_controller = RichProgressController(
                console, status, agent_statuses, ensemble_config.agents
            )

            # Provide the executor with direct progress control for user input
            executor._progress_controller = progress_controller

            async for event in executor.execute_streaming(ensemble_config, input_data):
                event_type = event["type"]

                # Handle the event and check if execution should continue
                should_continue = _handle_streaming_event(
                    event_type,
                    event,
                    agent_statuses,
                    ensemble_config,
                    status,
                    console,
                    output_format,
                    detailed,
                )

                # If event handler returns False, break the loop
                if not should_continue:
                    break


def _setup_fallback_monitoring(
    executor: Any,
) -> tuple[list[dict[str, Any]], Any]:
    """Set up fallback event monitoring and return events list and original emit."""
    fallback_events: list[dict[str, Any]] = []

    def capture_fallback_event(event_type: str, data: dict[str, Any]) -> None:
        """Capture fallback events during standard execution."""
        if event_type in [
            "agent_fallback_started",
            "agent_fallback_completed",
            "agent_fallback_failed",
        ]:
            fallback_events.append({"type": event_type, "data": data})

    # Temporarily replace the event emission to capture fallback events
    original_emit = executor._emit_performance_event
    executor._emit_performance_event = capture_fallback_event

    return fallback_events, original_emit


def _process_fallback_events_for_text(fallback_events: list[dict[str, Any]]) -> None:
    """Process captured fallback events for text output."""
    for event in fallback_events:
        event_type = event["type"]
        event_data = event["data"]
        if event_type == "agent_fallback_started":
            _handle_text_fallback_started(event_data)
        elif event_type == "agent_fallback_failed":
            _handle_text_fallback_failed(event_data)


def _display_json_results(
    result: dict[str, Any],
    ensemble_config: EnsembleConfig,
    fallback_events: list[dict[str, Any]],
) -> None:
    """Display results in JSON format with dependency info and fallback events."""
    import json

    # Add structured dependency information
    dependency_info = _create_structured_dependency_info(
        ensemble_config.agents, result["results"]
    )

    # Include fallback events and dependency info in JSON output
    output_data = result.copy()
    output_data["dependency_info"] = dependency_info
    if fallback_events:
        output_data["fallback_events"] = fallback_events
    click.echo(json.dumps(output_data, indent=2))


async def run_standard_execution(
    executor: Any,
    ensemble_config: EnsembleConfig,
    input_data: str,
    output_format: str,
    detailed: bool,
) -> None:
    """Run standard execution without streaming but with fallback event monitoring."""
    # Set up fallback event monitoring for text/JSON output
    fallback_events, original_emit = _setup_fallback_monitoring(executor)

    try:
        result = await executor.execute(ensemble_config, input_data)

        # Process any captured fallback events for text output
        if fallback_events and output_format == "text":
            _process_fallback_events_for_text(fallback_events)

        # Display results based on output format
        if output_format == "json":
            _display_json_results(result, ensemble_config, fallback_events)
        elif output_format == "text":
            # Use plain text output for clean piping
            display_plain_text_results(
                result["results"], result["metadata"], detailed, ensemble_config.agents
            )
        else:
            # Use Rich formatting for default output
            display_results(result["results"], result["metadata"], detailed)

    finally:
        # Restore original event emission
        executor._emit_performance_event = original_emit


def _display_adaptive_with_decisions(
    management_type: str, concurrency_decisions: list[dict[str, Any]]
) -> None:
    """Display adaptive resource management with concurrency decisions."""
    click.echo(f"Type: {management_type} (adaptive limits based on system resources)")

    final_decision = concurrency_decisions[-1]

    if "adaptive_limit" in final_decision:
        _display_adaptive_decision_details(final_decision, concurrency_decisions)
    else:
        click.echo(
            "Adaptive resource management enabled but no detailed metrics available"
        )


def _display_adaptive_decision_details(
    final_decision: dict[str, Any], concurrency_decisions: list[dict[str, Any]]
) -> None:
    """Display detailed adaptive decision metrics."""
    adaptive_limit = final_decision.get("adaptive_limit", "unknown")
    cpu_percent = final_decision.get("cpu_percent", 0.0)
    memory_percent = final_decision.get("memory_percent", 0.0)
    circuit_state = final_decision.get("circuit_breaker_state", "unknown")
    base_limit = final_decision.get("base_limit", "unknown")

    click.echo(
        f"Adaptive limit calculated: {adaptive_limit} "
        f"(CPU: {cpu_percent:.1f}%, Memory: {memory_percent:.1f}%, "
        f"Circuit: {circuit_state})"
    )
    click.echo(f"Base limit: {base_limit}")

    if len(concurrency_decisions) > 1:
        decisions_count = len(concurrency_decisions)
        click.echo(
            f"Concurrency adjustments: {decisions_count} decisions made "
            f"during execution"
        )


def _display_static_decisions(
    management_type: str, concurrency_decisions: list[dict[str, Any]]
) -> None:
    """Display resource management with decision data."""
    if management_type == "user_configured":
        click.echo(f"Type: {management_type} (user-controlled concurrency)")
    else:
        click.echo(f"Type: {management_type} (fixed concurrency limits)")

    final_decision = concurrency_decisions[-1]

    # Handle our new user_configured format
    if "configured_limit" in final_decision:
        limit = final_decision.get("configured_limit", "unknown")
        agent_count = final_decision.get("agent_count", "unknown")
        click.echo(
            f"Configured limit: {limit} concurrent agents "
            f"(for {agent_count} total agents)"
        )
    elif "static_limit" in final_decision:
        static_limit = final_decision.get("static_limit", "unknown")
        agent_count = final_decision.get("agent_count", "unknown")
        click.echo(
            f"Static limit applied: {static_limit} concurrent agents "
            f"(for {agent_count} total agents)"
        )


def _display_execution_metrics(execution_metrics: dict[str, Any]) -> None:
    """Display detailed execution metrics for research purposes."""
    peak_cpu = execution_metrics.get("peak_cpu", 0.0)
    avg_cpu = execution_metrics.get("avg_cpu", 0.0)
    peak_memory = execution_metrics.get("peak_memory", 0.0)
    avg_memory = execution_metrics.get("avg_memory", 0.0)
    sample_count = execution_metrics.get("sample_count", 0)

    click.echo(
        f"Peak resource usage during execution: "
        f"CPU {peak_cpu:.1f}%, Memory: {peak_memory:.1f}%"
    )
    click.echo(
        f"Average resource usage during execution: "
        f"CPU {avg_cpu:.1f}%, Memory {avg_memory:.1f}%"
    )
    click.echo(f"Monitoring details: {sample_count} samples collected")

    _display_raw_samples(execution_metrics)

    if sample_count == 0:
        click.echo(
            "Note: No monitoring samples collected - execution may have been too fast"
        )


def _display_raw_samples(execution_metrics: dict[str, Any]) -> None:
    """Display raw CPU and memory samples for research analysis."""
    raw_cpu_samples = execution_metrics.get("raw_cpu_samples")
    raw_memory_samples = execution_metrics.get("raw_memory_samples")

    if raw_cpu_samples and raw_memory_samples:
        cpu_sample_str = ", ".join(f"{s:.1f}" for s in raw_cpu_samples)
        memory_sample_str = ", ".join(
            f"{s:.1f}" for s in raw_memory_samples[: len(raw_cpu_samples)]
        )
        click.echo(
            f"Sample data (first 10): CPU: [{cpu_sample_str}]%, "
            f"Memory: [{memory_sample_str}]%"
        )


def _display_simplified_metrics(execution_metrics: dict[str, Any]) -> None:
    """Display simplified execution metrics for user feedback."""
    if not execution_metrics:
        click.echo("No monitoring data collected")
        return

    peak_cpu = execution_metrics.get("peak_cpu", 0.0)
    avg_cpu = execution_metrics.get("avg_cpu", 0.0)
    peak_memory = execution_metrics.get("peak_memory", 0.0)
    avg_memory = execution_metrics.get("avg_memory", 0.0)
    sample_count = execution_metrics.get("sample_count", 0)

    click.echo(f"Peak usage: CPU {peak_cpu:.1f}%, Memory {peak_memory:.1f}%")
    click.echo(f"Average usage: CPU {avg_cpu:.1f}%, Memory {avg_memory:.1f}%")
    click.echo(f"Monitoring: {sample_count} samples collected")


def _display_phase_resource_usage(phase_data: dict[str, Any]) -> None:
    """Display resource usage for a single phase."""
    peak_cpu = phase_data.get("peak_cpu")
    avg_cpu = phase_data.get("avg_cpu")
    peak_memory = phase_data.get("peak_memory")
    avg_memory = phase_data.get("avg_memory")
    sample_count = phase_data.get("sample_count", 0)

    if peak_cpu is not None and avg_cpu is not None and sample_count > 0:
        # Show detailed peak/average metrics
        click.echo(f"  Peak usage: CPU {peak_cpu:.1f}%, Memory {peak_memory:.1f}%")
        click.echo(f"  Avg usage: CPU {avg_cpu:.1f}%, Memory {avg_memory:.1f}%")
        click.echo(f"  Samples: {sample_count} collected")
    else:
        # Fallback to final snapshot if available
        final_cpu = phase_data.get("final_cpu_percent")
        final_memory = phase_data.get("final_memory_percent")
        if final_cpu is not None and final_memory is not None:
            click.echo(f"  Resources: CPU {final_cpu:.1f}%, Memory {final_memory:.1f}%")
        else:
            click.echo("  Resources: No monitoring data available")


def _display_phase_timing(
    phase_data: dict[str, Any], phase_index: int, phase_metrics: list[dict[str, Any]]
) -> None:
    """Display timing information for a single phase."""
    start_time = phase_data.get("start_time")
    end_time = phase_data.get("end_time")
    if start_time and end_time:
        # Convert to relative time from start
        relative_start = 0.0 if phase_index == 0 else start_time
        first_start = phase_metrics[0].get("start_time", start_time)
        relative_end = end_time - first_start
        click.echo(f"  Timing: {relative_start:.2f}s - {relative_end:.2f}s")


def _display_phase_statistics(phase_metrics: list[dict[str, Any]]) -> None:
    """Display per-phase execution statistics."""
    click.echo("Per-Phase Statistics")
    click.echo("===================")

    for phase_data in phase_metrics:
        phase_index = phase_data.get("phase_index", "?")
        agent_names = phase_data.get("agent_names", [])
        duration = phase_data.get("duration_seconds", 0.0)
        agent_count = phase_data.get("agent_count", len(agent_names))

        click.echo(f"Phase {phase_index + 1}: {agent_count} agents ({duration:.2f}s)")

        if agent_names:
            agent_list = ", ".join(agent_names)
            click.echo(f"  Agents: {agent_list}")

        # Show resource usage
        _display_phase_resource_usage(phase_data)

        # Show timing details if available
        _display_phase_timing(phase_data, phase_index, phase_metrics)

        click.echo()  # Empty line between phases


def _display_adaptive_resource_metrics_text(adaptive_stats: dict[str, Any]) -> None:
    """Display simplified resource management metrics."""
    management_type = adaptive_stats.get("management_type", "user_configured")
    concurrency_decisions = adaptive_stats.get("concurrency_decisions", [])
    execution_metrics = adaptive_stats.get("execution_metrics", {})

    click.echo()
    click.echo("Resource Management")
    click.echo("==================")

    # Show concurrency configuration
    if concurrency_decisions:
        _display_static_decisions(management_type, concurrency_decisions)
    else:
        click.echo(f"Type: {management_type} (user-controlled concurrency)")

    # Always show execution metrics when available
    if execution_metrics:
        click.echo()
        _display_simplified_metrics(execution_metrics)
    else:
        click.echo("No monitoring data collected")

    # Show per-phase statistics if available
    phase_metrics = adaptive_stats.get("phase_metrics", [])
    if phase_metrics:
        click.echo()
        _display_phase_statistics(phase_metrics)

    # Add user guidance for performance optimization
    _display_performance_guidance(adaptive_stats)


def _display_performance_guidance(adaptive_stats: dict[str, Any]) -> None:
    """Display helpful guidance for optimizing performance settings."""
    execution_metrics = adaptive_stats.get("execution_metrics", {})
    concurrency_decisions = adaptive_stats.get("concurrency_decisions", [])

    if not execution_metrics or not concurrency_decisions:
        return

    # Get the current configuration
    final_decision = concurrency_decisions[-1]
    current_limit = final_decision.get(
        "configured_limit", final_decision.get("static_limit")
    )
    agent_count = final_decision.get("agent_count", 0)

    if not current_limit:
        return

    # Get performance metrics
    peak_cpu = execution_metrics.get("peak_cpu", 0)
    peak_memory = execution_metrics.get("peak_memory", 0)
    sample_count = execution_metrics.get("sample_count", 0)

    click.echo()
    click.echo("💡 Performance Optimization Tips:")

    # High resource usage guidance
    if peak_cpu > 80 or peak_memory > 85:
        click.echo(
            f"   • High resource usage detected "
            f"(CPU: {peak_cpu:.1f}%, Memory: {peak_memory:.1f}%)"
        )
        if current_limit > 1:
            click.echo(
                f"   • Consider reducing max_concurrent from {current_limit} "
                f"to {current_limit - 1}"
            )
        click.echo("   • Monitor system stability during execution")

    # Low resource usage guidance
    elif peak_cpu < 20 and peak_memory < 50 and current_limit < agent_count:
        click.echo(
            f"   • System has capacity "
            f"(CPU: {peak_cpu:.1f}%, Memory: {peak_memory:.1f}%)"
        )
        suggested_limit = min(agent_count, current_limit + 2)
        click.echo(
            f"   • Consider increasing max_concurrent from {current_limit} "
            f"to {suggested_limit}"
        )
        click.echo("   • This could reduce execution time")

    # Sample count guidance
    if sample_count < 5:
        click.echo(
            f"   • Low monitoring samples ({sample_count}) - execution was very fast"
        )
        click.echo(
            "   • Consider testing with larger ensembles for better performance data"
        )

    # Configuration guidance
    click.echo("   • Adjust max_concurrent in your performance configuration")
    click.echo("   • Monitor execution time vs resource usage to find optimal settings")
