"""Generate contextual topics for Matrix rooms using AI."""

from __future__ import annotations

from typing import TYPE_CHECKING

import nio
from agno.agent import Agent
from pydantic import BaseModel, Field

from mindroom import model_loading
from mindroom.ai_runtime import cached_agent_run
from mindroom.entity_resolution import configured_routable_entity_names_for_room
from mindroom.logging_config import get_logger
from mindroom.matrix import state as matrix_state

if TYPE_CHECKING:
    from mindroom.config.main import Config
    from mindroom.constants import RuntimePaths

logger = get_logger(__name__)


class _RoomTopic(BaseModel):
    """Structured room topic response."""

    topic: str = Field(description="The room topic - concise, informative, with emoji")


def _configured_entity_display_names_for_room(
    room_key: str,
    config: Config,
    runtime_paths: RuntimePaths,
) -> list[str]:
    """Return configured agent and team display names for one room key or ID."""
    room_id = matrix_state.get_room_id(room_key, runtime_paths) or room_key
    return [
        (config.agents[entity_name].display_name or entity_name)
        if entity_name in config.agents
        else (config.teams[entity_name].display_name or entity_name)
        for entity_name in configured_routable_entity_names_for_room(config, room_id, runtime_paths)
    ]


async def generate_room_topic_ai(
    room_key: str,
    room_name: str,
    config: Config,
    runtime_paths: RuntimePaths,
) -> str | None:
    """Generate a contextual topic for a room using AI based on its purpose and configured entities.

    Args:
        room_key: The room key/alias (e.g., 'dev', 'analysis', 'lobby')
        room_name: Display name for the room
        config: Configuration with agent settings
        runtime_paths: Explicit runtime context for model selection and session scoping

    Returns:
        A contextual topic string for the room

    """
    configured_entity_list = ", ".join(
        _configured_entity_display_names_for_room(room_key, config, runtime_paths),
    )

    prompt = f"""Generate a concise, informative room topic for a MindRoom Matrix room.

Context about MindRoom:
MindRoom is a platform that frees AI agents from being trapped in single apps. Key features:
- AI agents with persistent memory that work across all platforms (Slack, Discord, Telegram, WhatsApp)
- Agents collaborate naturally in threads and remember everything across sessions
- Built on Matrix protocol for secure, federated communication
- 100+ integrations with tools like Gmail, GitHub, Spotify, Home Assistant
- Self-hosted or cloud options with military-grade encryption

Room details:
- Room key/alias: {room_key}
- Room name: {room_name}
- Configured agents and teams: {configured_entity_list or "No specific agents or teams configured yet"}

Create a topic that:
1. Describes the room's purpose based on its name
2. Mentions the AI agents, teams, or capabilities available
3. Highlights MindRoom's persistent memory or cross-platform nature when relevant
4. Is welcoming and informative
5. Uses 1-2 relevant emojis
6. Is under 100 characters
7. Follows this format: [emoji] [Description] • [Capabilities/Purpose]

Examples:
- 💻 Development Hub • AI agents that remember your code patterns across sessions
- 📊 Analysis Center • Persistent insights with cross-platform data access
- 🏠 Main Lobby • Your AI team headquarters with continuous memory
- 💰 Finance Room • AI agents tracking markets 24/7 with full context
- 🔬 Research Lab • Collaborative AI exploration with shared knowledge

Generate the topic:"""

    model = model_loading.get_model_instance(config, runtime_paths, "default")

    agent = Agent(
        name="TopicGenerator",
        role="Generate contextual room topics",
        model=model,
        output_schema=_RoomTopic,
        telemetry=False,
    )

    session_id = f"topic_{room_key}"
    try:
        response = await cached_agent_run(
            agent=agent,
            run_input=prompt,
            session_id=session_id,
        )
    except Exception:
        logger.exception("room_topic_generation_failed", room_key=room_key, session_id=session_id)
        return None
    content = response.content
    if not isinstance(content, _RoomTopic):
        logger.warning(
            "room_topic_generation_unexpected_type",
            room_key=room_key,
            content_type=type(content).__name__,
        )
        return str(content) if content else None
    return content.topic


async def ensure_room_has_topic(
    client: nio.AsyncClient,
    room_id: str,
    room_key: str,
    room_name: str,
    config: Config,
    runtime_paths: RuntimePaths,
) -> bool:
    """Ensure a room has a topic set, generating one if needed.

    Args:
        client: Matrix client
        room_id: The room ID
        room_key: The room key/alias
        room_name: Display name for the room
        config: Configuration with agent settings
        runtime_paths: Explicit runtime context for topic generation

    Returns:
        True if topic was set or already exists, False on error

    """
    response = await client.room_get_state_event(room_id, "m.room.topic")
    if isinstance(response, nio.RoomGetStateEventResponse) and response.content.get("topic"):
        logger.debug(
            "room_topic_already_present",
            room_id=room_id,
            room_key=room_key,
            topic=response.content["topic"],
        )
        return True

    # Generate and set topic
    logger.info("generate_room_topic", room_id=room_id, room_key=room_key, room_name=room_name)
    topic = await generate_room_topic_ai(room_key, room_name, config, runtime_paths)
    if topic is None:
        logger.warning("generate_room_topic_failed", room_id=room_id, room_key=room_key)
        return False

    # Set the topic
    response = await client.room_put_state(
        room_id=room_id,
        event_type="m.room.topic",
        content={"topic": topic},
    )

    if isinstance(response, nio.RoomPutStateResponse):
        logger.info("room_topic_set", room_id=room_id, room_key=room_key, topic=topic)
        return True

    logger.warning("set_room_topic_failed", room_id=room_id, room_key=room_key, error=str(response))
    return False
