"""Crafting commands."""

from collections import Counter

from mudlib.commands import CommandDefinition, register
from mudlib.crafting import recipes
from mudlib.player import Player
from mudlib.things import spawn_thing, thing_templates


async def cmd_craft(player: Player, args: str) -> None:
    """Craft an item from a recipe.

    Args:
        player: The player crafting
        args: Recipe name
    """
    if not args:
        await player.send("Usage: craft <recipe>\r\n")
        return

    recipe_name = args.strip().lower()

    # Find recipe by name (case-insensitive, prefix match)
    matching_recipes = [
        name for name in recipes if name.lower().startswith(recipe_name)
    ]

    if not matching_recipes:
        await player.send(f"Unknown recipe: {args}\r\n")
        return

    if len(matching_recipes) > 1:
        await player.send(
            f"Ambiguous recipe name. Matches: {', '.join(matching_recipes)}\r\n"
        )
        return

    recipe = recipes[matching_recipes[0]]

    # Count required ingredients
    required = Counter(ingredient.lower() for ingredient in recipe.ingredients)

    # Count available ingredients in inventory
    inventory = player.contents
    available = Counter(obj.name.lower() for obj in inventory)

    # Check if player has all ingredients
    missing = []
    for ingredient, count in required.items():
        if available[ingredient] < count:
            needed = count - available[ingredient]
            missing.append(f"{ingredient} (need {needed} more)")

    if missing:
        await player.send(f"Missing ingredients: {', '.join(missing)}\r\n")
        return

    # Check if result template exists
    if recipe.result not in thing_templates:
        await player.send(
            f"Error: Recipe result '{recipe.result}' template not found.\r\n"
        )
        return

    # Consume ingredients
    consumed = Counter()
    for obj in list(inventory):
        obj_name = obj.name.lower()
        if obj_name in required and consumed[obj_name] < required[obj_name]:
            obj.move_to(None)  # Remove from world
            consumed[obj_name] += 1

    # Create result item
    result_template = thing_templates[recipe.result]
    spawn_thing(result_template, player)

    await player.send(f"You craft a {result_template.name}.\r\n")


async def cmd_recipes(player: Player, args: str) -> None:
    """List available recipes.

    Args:
        player: The player viewing recipes
        args: Optional recipe name for details
    """
    if not recipes:
        await player.send("No recipes available.\r\n")
        return

    if args:
        # Show details for specific recipe
        recipe_name = args.strip().lower()
        matching = [name for name in recipes if name.lower().startswith(recipe_name)]

        if not matching:
            await player.send(f"Unknown recipe: {args}\r\n")
            return

        if len(matching) > 1:
            await player.send(
                f"Ambiguous recipe name. Matches: {', '.join(matching)}\r\n"
            )
            return

        recipe = recipes[matching[0]]
        ingredient_counts = Counter(recipe.ingredients)
        ingredient_list = ", ".join(
            f"{count}x {name}" if count > 1 else name
            for name, count in sorted(ingredient_counts.items())
        )

        await player.send(
            f"Recipe: {recipe.name}\r\n"
            f"{recipe.description}\r\n"
            f"Ingredients: {ingredient_list}\r\n"
            f"Result: {recipe.result}\r\n"
        )
    else:
        # List all recipes
        await player.send("Available recipes:\r\n")
        for name, recipe in sorted(recipes.items()):
            await player.send(f"  {name}: {recipe.description}\r\n")


register(CommandDefinition("craft", cmd_craft, help="Craft items from recipes."))
register(
    CommandDefinition("recipes", cmd_recipes, help="List available crafting recipes.")
)
