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

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"
            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


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."""
    # Group agents by dependency level
    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)

    # Build horizontal graph: A,B,C → D → E,F → G
    graph_parts = []
    max_level = max(agents_by_level.keys()) if agents_by_level else 0

    for level in range(max_level + 1):
        if level not in agents_by_level:
            continue

        level_agents = agents_by_level[level]
        agent_displays = []

        for agent in level_agents:
            name = agent["name"]
            status = agent_statuses.get(name, "pending")

            # Status indicators with plain text symbols
            if status == "running":
                agent_displays.append(f"◐ {name}")
            elif status == "completed":
                agent_displays.append(f"✓ {name}")
            elif status == "failed":
                agent_displays.append(f"✗ {name}")
            else:
                agent_displays.append(f"○ {name}")

        # Join agents at same level with commas
        level_text = ", ".join(agent_displays)
        graph_parts.append(level_text)

    # Join levels with arrows
    return " → ".join(graph_parts)


def create_dependency_graph_with_status(
    agents: list[dict[str, Any]], agent_statuses: dict[str, str]
) -> str:
    """Create horizontal dependency graph with status indicators."""
    # Group agents by dependency level
    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)

    # Build horizontal graph: A,B,C → D → E,F → G
    graph_parts = []
    max_level = max(agents_by_level.keys()) if agents_by_level else 0

    for level in range(max_level + 1):
        if level not in agents_by_level:
            continue

        level_agents = agents_by_level[level]
        agent_displays = []

        for agent in level_agents:
            name = agent["name"]
            status = agent_statuses.get(name, "pending")

            # Status indicators with symbols
            if status == "running":
                agent_displays.append(f"[yellow]◐[/yellow] [yellow]{name}[/yellow]")
            elif status == "completed":
                agent_displays.append(f"[green]✓[/green] [green]{name}[/green]")
            elif status == "failed":
                agent_displays.append(f"[red]✗[/red] [red]{name}[/red]")
            else:
                agent_displays.append(f"[dim]○[/dim] [dim]{name}[/dim]")

        # Join agents at same level with commas
        level_text = ", ".join(agent_displays)
        graph_parts.append(level_text)

    # Join levels with arrows
    return " → ".join(graph_parts)


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"]
            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 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)

    # Debug: print to see what's happening
    # print(f"DEBUG: final_agent={final_agent}, results keys={list(results.keys())}")
    # Uncomment for debugging

    markdown_content = []

    if final_agent and results[final_agent].get("status") == "success":
        response = results[final_agent]["response"]
        # Add a clear header to indicate this is the final result
        markdown_content.append("## Result\n\n")
        # Format as code block if it looks like code, otherwise as regular text
        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:
        # 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")
            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("**❌ 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_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 == "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,
        )

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

    elif event_type == "execution_started":
        # Show initial dependency tree when execution starts
        current_tree = create_dependency_tree(ensemble_config.agents, agent_statuses)
        status.update(current_tree)

    elif event_type == "agent_started":
        # Agent has started execution
        event_data = event["data"]
        agent_name = event_data["agent_name"]
        agent_statuses[agent_name] = "running"

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

    elif event_type == "agent_completed":
        # Agent has completed execution
        event_data = event["data"]
        agent_name = event_data["agent_name"]
        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)

    elif event_type == "execution_progress":
        # Just update the tree without elapsed time overlay to avoid flickering
        # The elapsed time will be shown in the final completion message
        current_tree = create_dependency_tree(ensemble_config.agents, agent_statuses)
        status.update(current_tree)

    elif event_type == "agent_fallback_started":
        # Show fallback message without disrupting the tree display
        event_data = event["data"]
        agent_name = event_data["agent_name"]

        # Update agent status to running (attempting fallback)
        agent_statuses[agent_name] = "running"

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

        _handle_fallback_started_event(console, event_data)

    elif event_type == "agent_fallback_completed":
        # Update agent status to completed
        event_data = event["data"]
        agent_name = event_data["agent_name"]
        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)

    elif event_type == "agent_fallback_failed":
        # Update agent status to failed
        event_data = event["data"]
        agent_name = event_data["agent_name"]
        agent_statuses[agent_name] = "failed"

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

        _handle_fallback_failed_event(console, event_data)

    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,
        )

    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:
            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")
