"""Talk and reply commands for NPC conversations."""

from mudlib.commands import CommandDefinition, register
from mudlib.conversation import (
    advance_conversation,
    end_conversation,
    get_conversation,
    start_conversation,
)
from mudlib.dialogue import DialogueNode, DialogueTree
from mudlib.entity import Mob
from mudlib.player import Player
from mudlib.targeting import find_entity_on_tile

# Global registry of dialogue trees (keyed by npc_name)
dialogue_trees: dict[str, DialogueTree] = {}


def _format_dialogue_node(npc: Mob, node: DialogueNode) -> str:
    """Format a dialogue node for display.

    Args:
        npc: The NPC speaking
        node: The dialogue node to format

    Returns:
        Formatted text with NPC name, text, and numbered choices
    """
    lines = []

    # NPC says line
    lines.append(f'{npc.name.capitalize()} says, "{node.text}"')
    lines.append("")

    # Numbered choices (if any)
    if node.choices:
        for i, choice in enumerate(node.choices, 1):
            lines.append(f"  {i}. {choice.text}")

    return "\r\n".join(lines) + "\r\n"


async def cmd_talk(player: Player, args: str) -> None:
    """Start or continue a conversation with an NPC.

    Usage: talk <npc_name>
    """
    npc_name = args.strip().lower()
    if not npc_name:
        await player.send("Talk to whom?\r\n")
        return

    # Check if already in conversation
    conv = get_conversation(player)
    if conv:
        # Show current node
        current_node = conv.tree.nodes[conv.current_node]
        output = _format_dialogue_node(conv.npc, current_node)
        await player.send(output)
        return

    # Find the NPC in the same room
    target = find_entity_on_tile(npc_name, player, z_filter=False)
    if target is None:
        await player.send("You don't see that person here.\r\n")
        return

    # Check it's a Mob with npc_name set
    if not isinstance(target, Mob) or target.npc_name is None:
        await player.send("You can't talk to that.\r\n")
        return

    # Check if dialogue tree exists for this NPC
    tree = dialogue_trees.get(target.npc_name)
    if tree is None:
        await player.send("They don't have anything to say right now.\r\n")
        return

    # Start the conversation
    root_node = start_conversation(player, target, tree)

    # Display the root node
    output = _format_dialogue_node(target, root_node)
    await player.send(output)


async def cmd_reply(player: Player, args: str) -> None:
    """Reply to an NPC in an active conversation.

    Usage: reply <number>
    """
    choice_str = args.strip()
    if not choice_str:
        await player.send("Reply with which choice number?\r\n")
        return

    # Check if in a conversation
    conv = get_conversation(player)
    if conv is None:
        await player.send("You're not in a conversation.\r\n")
        return

    # Parse choice number
    try:
        choice_num = int(choice_str)
    except ValueError:
        await player.send("Please enter a number.\r\n")
        return

    # Advance conversation
    next_node = advance_conversation(player, choice_num)
    if next_node is None:
        await player.send("Invalid choice.\r\n")
        return

    # Display the next node
    output = _format_dialogue_node(conv.npc, next_node)
    await player.send(output)

    # End conversation if this is a terminal node
    if len(next_node.choices) == 0:
        end_conversation(player)


register(CommandDefinition("talk", cmd_talk, help="Start conversation with an NPC"))
register(CommandDefinition("reply", cmd_reply, help="Reply in a conversation"))
