"""Test collision detection when registering commands."""

import logging

import pytest

from mudlib.commands import CommandDefinition, _registry, register


@pytest.fixture(autouse=True)
def clean_registry():
    """Save and restore registry around each test."""
    saved = dict(_registry)
    _registry.clear()
    yield
    _registry.clear()
    _registry.update(saved)


async def dummy_handler(player, args):
    """Placeholder command handler."""
    pass


async def other_handler(player, args):
    """Another placeholder command handler."""
    pass


def test_registering_command_adds_to_registry():
    """Baseline: registering a command adds it to registry."""
    defn = CommandDefinition(name="test", handler=dummy_handler)
    register(defn)
    assert "test" in _registry
    assert _registry["test"] is defn


def test_registering_same_command_again_does_not_warn(caplog):
    """Registering same command definition again does not warn."""
    defn = CommandDefinition(name="test", handler=dummy_handler)

    with caplog.at_level(logging.WARNING):
        register(defn)
        register(defn)

    assert len(caplog.records) == 0


def test_registering_different_command_with_same_name_warns(caplog):
    """Registering different command with same name warns."""
    defn1 = CommandDefinition(name="test", handler=dummy_handler)
    defn2 = CommandDefinition(name="test", handler=other_handler)

    with caplog.at_level(logging.WARNING):
        register(defn1)
        register(defn2)

    assert len(caplog.records) == 1
    assert "collision" in caplog.records[0].message.lower()
    assert "test" in caplog.records[0].message
    assert _registry["test"] is defn2  # last-registered wins


def test_command_alias_collides_with_existing_command_name(caplog):
    """Registering command whose alias collides with existing name warns."""
    defn1 = CommandDefinition(name="north", handler=dummy_handler)
    defn2 = CommandDefinition(name="navigate", handler=other_handler, aliases=["north"])

    with caplog.at_level(logging.WARNING):
        register(defn1)
        register(defn2)

    assert len(caplog.records) == 1
    assert "collision" in caplog.records[0].message.lower()
    assert "north" in caplog.records[0].message


def test_command_alias_collides_with_different_command_alias(caplog):
    """Registering command whose alias collides with different command's alias warns."""
    defn1 = CommandDefinition(name="southwest", handler=dummy_handler, aliases=["sw"])
    defn2 = CommandDefinition(name="sweep", handler=other_handler, aliases=["sw"])

    with caplog.at_level(logging.WARNING):
        register(defn1)
        register(defn2)

    assert len(caplog.records) == 1
    assert "collision" in caplog.records[0].message.lower()
    assert "sw" in caplog.records[0].message


def test_warning_message_includes_both_command_names(caplog):
    """Warning message includes both the existing and new command names."""
    defn1 = CommandDefinition(name="existing", handler=dummy_handler)
    defn2 = CommandDefinition(name="newcomer", handler=other_handler)

    with caplog.at_level(logging.WARNING):
        register(defn1)
        register(defn2)  # both have name "newcomer" but defn2 overwrites

    # Re-register to trigger collision
    defn3 = CommandDefinition(name="existing", handler=other_handler)
    with caplog.at_level(logging.WARNING):
        caplog.clear()
        register(defn3)

    assert len(caplog.records) == 1
    record = caplog.records[0].message
    assert "existing" in record
    # Should show both the existing command name and the new one
    assert "existing" in record


def test_same_definition_multiple_aliases_no_warning(caplog):
    """Same definition registering multiple aliases to itself doesn't warn."""
    defn = CommandDefinition(name="test", handler=dummy_handler, aliases=["t", "tst"])

    with caplog.at_level(logging.WARNING):
        register(defn)

    assert len(caplog.records) == 0
    assert _registry["test"] is defn
    assert _registry["t"] is defn
    assert _registry["tst"] is defn
