"""Matrix mention utilities."""

import re
from typing import TYPE_CHECKING, Any

from mindroom.config.main import Config
from mindroom.matrix.identity import MatrixID, mindroom_namespace
from mindroom.matrix.message_builder import build_message_content, markdown_to_html
from mindroom.tool_system.events import build_tool_trace_content

if TYPE_CHECKING:
    from mindroom.tool_system.events import ToolTraceEntry


def parse_mentions_in_text(text: str, sender_domain: str, config: Config) -> tuple[str, list[str], str]:
    """Parse text for agent mentions and return processed text with user IDs.

    Args:
        text: Text that may contain @agent_name mentions
        sender_domain: Domain part of the sender's user ID (e.g., "localhost" from "@user:localhost")
        config: Application configuration

    Returns:
        Tuple of (plain_text, list_of_mentioned_user_ids, markdown_text_with_links)

    """
    # Pattern to match @agent_name (with optional @mindroom_ prefix or domain)
    # Matches: @calculator, @mindroom_calculator, @mindroom_calculator:localhost
    pattern = r"@(mindroom_)?(\w+)(?::[^\s]+)?"

    # Find all mentions and process them
    mentions_data = []
    for match in re.finditer(pattern, text):
        mention_info = _process_mention(match, config, sender_domain)
        if mention_info:
            mentions_data.append(mention_info)

    # Build outputs from collected data
    plain_text = text
    markdown_text = text
    mentioned_user_ids: list[str] = []

    # Apply replacements (reverse order to preserve positions)
    for original, user_id, display_name in reversed(mentions_data):
        # Plain text: replace with full Matrix ID
        plain_text = plain_text.replace(original, user_id, 1)

        # Markdown: replace with clickable link
        link = f"[@{display_name}](https://matrix.to/#/{user_id})"
        markdown_text = markdown_text.replace(original, link, 1)

        # Collect unique user IDs
        if user_id not in mentioned_user_ids:
            mentioned_user_ids.insert(0, user_id)  # Insert at start to maintain order

    return plain_text, mentioned_user_ids, markdown_text


def _process_mention(match: re.Match, config: Config, sender_domain: str) -> tuple[str, str, str] | None:
    """Process a single mention match and return replacement data.

    Args:
        match: The regex match object
        config: The loaded config
        sender_domain: Domain for constructing Matrix IDs

    Returns:
        Tuple of (original_text, matrix_user_id, display_name) or None if not a valid agent

    """
    original = match.group(0)
    name = match.group(2)

    # Skip user-like mentions (e.g. mindroom_user_*)
    if name.startswith("user_"):
        return None

    # Try to find the agent (case-insensitive), accepting optional namespace suffix.
    candidate_names = [name]
    namespace = mindroom_namespace()
    if namespace:
        suffix = f"_{namespace}"
        if name.lower().endswith(suffix):
            stripped = name[: -len(suffix)]
            if stripped:
                candidate_names.append(stripped)

    agent_name = None
    for candidate_name in candidate_names:
        candidate_lower = candidate_name.lower()
        for config_agent_name in config.agents:
            if config_agent_name.lower() == candidate_lower:
                agent_name = config_agent_name
                break
        if agent_name:
            break

    if agent_name:
        agent_config = config.agents[agent_name]
        user_id = MatrixID.from_agent(agent_name, sender_domain).full_id
        return (original, user_id, agent_config.display_name)

    return None


def format_message_with_mentions(
    config: Config,
    text: str,
    sender_domain: str = "localhost",
    thread_event_id: str | None = None,
    reply_to_event_id: str | None = None,
    latest_thread_event_id: str | None = None,
    tool_trace: list["ToolTraceEntry"] | None = None,
    extra_content: dict[str, Any] | None = None,
) -> dict[str, Any]:
    """Parse text for mentions and create properly formatted Matrix message.

    This is the universal function that should be used everywhere.

    Args:
        config: Application configuration
        text: Message text that may contain @agent_name mentions
        sender_domain: Domain part of the sender's user ID
        thread_event_id: Optional thread root event ID
        reply_to_event_id: Optional event ID to reply to (for genuine replies)
        latest_thread_event_id: Optional latest event ID in thread (for fallback compatibility)
        tool_trace: Optional structured tool trace metadata
        extra_content: Optional custom metadata fields merged into content

    Returns:
        Properly formatted content dict for room_send

    """
    plain_text, mentioned_user_ids, markdown_text = parse_mentions_in_text(text, sender_domain, config)

    # Convert markdown (with links) to HTML
    # The markdown converter will properly handle the [@DisplayName](url) format
    formatted_html = markdown_to_html(markdown_text)
    tool_trace_content = build_tool_trace_content(tool_trace)
    merged_extra_content: dict[str, Any] = {}
    if tool_trace_content:
        merged_extra_content.update(tool_trace_content)
    if extra_content:
        merged_extra_content.update(extra_content)
    inherited_mentions = merged_extra_content.pop("m.mentions", None)
    inherited_user_ids = inherited_mentions.get("user_ids", []) if isinstance(inherited_mentions, dict) else []
    merged_mentioned_user_ids = list(mentioned_user_ids)
    for user_id in inherited_user_ids:
        if isinstance(user_id, str) and user_id not in merged_mentioned_user_ids:
            merged_mentioned_user_ids.append(user_id)

    return build_message_content(
        body=plain_text,
        formatted_body=formatted_html,
        mentioned_user_ids=merged_mentioned_user_ids,
        thread_event_id=thread_event_id,
        reply_to_event_id=reply_to_event_id,
        latest_thread_event_id=latest_thread_event_id,
        extra_content=merged_extra_content or None,
    )
