"""Shared utilities for the world route submodules."""

import math

# Agent color mapping — consistent with Matrix visual identity
_AGENT_COLORS: dict[str, str] = {
    "timmy": "#FFD700",  # Gold
    "orchestrator": "#FFD700",  # Gold
    "perplexity": "#3B82F6",  # Blue
    "replit": "#F97316",  # Orange
    "kimi": "#06B6D4",  # Cyan
    "claude": "#A855F7",  # Purple
    "researcher": "#10B981",  # Emerald
    "coder": "#EF4444",  # Red
    "writer": "#EC4899",  # Pink
    "memory": "#8B5CF6",  # Violet
    "experimenter": "#14B8A6",  # Teal
    "forge": "#EF4444",  # Red (coder alias)
    "seer": "#10B981",  # Emerald (researcher alias)
    "quill": "#EC4899",  # Pink (writer alias)
    "echo": "#8B5CF6",  # Violet (memory alias)
    "lab": "#14B8A6",  # Teal (experimenter alias)
}

# Agent shape mapping for 3D visualization
_AGENT_SHAPES: dict[str, str] = {
    "timmy": "sphere",
    "orchestrator": "sphere",
    "perplexity": "cube",
    "replit": "cylinder",
    "kimi": "dodecahedron",
    "claude": "octahedron",
    "researcher": "icosahedron",
    "coder": "cube",
    "writer": "cone",
    "memory": "torus",
    "experimenter": "tetrahedron",
    "forge": "cube",
    "seer": "icosahedron",
    "quill": "cone",
    "echo": "torus",
    "lab": "tetrahedron",
}

# Default fallback values
_DEFAULT_COLOR = "#9CA3AF"  # Gray
_DEFAULT_SHAPE = "sphere"
_DEFAULT_STATUS = "available"


def _get_agent_color(agent_id: str) -> str:
    """Get the Matrix color for an agent."""
    return _AGENT_COLORS.get(agent_id.lower(), _DEFAULT_COLOR)


def _get_agent_shape(agent_id: str) -> str:
    """Get the Matrix shape for an agent."""
    return _AGENT_SHAPES.get(agent_id.lower(), _DEFAULT_SHAPE)


def _compute_circular_positions(count: int, radius: float = 3.0) -> list[dict[str, float]]:
    """Compute circular positions for agents in the Matrix.

    Agents are arranged in a circle on the XZ plane at y=0.
    """
    positions = []
    for i in range(count):
        angle = (2 * math.pi * i) / count
        x = radius * math.cos(angle)
        z = radius * math.sin(angle)
        positions.append({"x": round(x, 2), "y": 0.0, "z": round(z, 2)})
    return positions


def _get_client_ip(request) -> str:
    """Extract client IP from request, respecting X-Forwarded-For header."""
    # Check for forwarded IP (when behind proxy)
    forwarded = request.headers.get("X-Forwarded-For")
    if forwarded:
        # Take the first IP in the chain
        return forwarded.split(",")[0].strip()
    # Fall back to direct client IP
    if request.client:
        return request.client.host
    return "unknown"
