package thb.jeanluc.adventure.game;

import thb.jeanluc.adventure.model.Combination;
import thb.jeanluc.adventure.model.item.Item;

/**
 * Applies {@code use X on Y} item combinations. Stateless utility, mirroring
 * {@link Conditions}/{@link Effects}/{@link Light}. Operands resolve from the
 * player's inventory or the current room.
 */
public final class Combinations {

    private Combinations() {
    }

    /**
     * Attempts to combine the two named items. Prints a resolution error if an
     * operand is absent, the recipe's {@code failText} (or a generic line) if a
     * recipe's requirements are unmet, "Nothing happens." if there is no recipe,
     * or applies consume/produce/effects + the response on success.
     */
    public static void tryUse(GameContext ctx, String idX, String idY) {
        if (!present(ctx, idX)) {
            ctx.getIo().write(noSuch(idX));
            return;
        }
        if (!present(ctx, idY)) {
            ctx.getIo().write(noSuch(idY));
            return;
        }
        Combination c = ctx.getWorld().getCombinations().get(Combination.key(idX, idY));
        if (c == null) {
            ctx.getIo().write("Nothing happens.");
            return;
        }
        if (!Conditions.all(c.requires(), ctx)) {
            ctx.getIo().write(c.failText() != null ? c.failText() : "Nothing happens.");
            return;
        }
        for (String id : c.consume()) {
            removeFromAnywhere(ctx, id);
        }
        if (c.produce() != null) {
            Item produced = ctx.getWorld().getItems().get(c.produce());
            if (produced != null) {
                ctx.getPlayer().addItem(produced);
            }
        }
        Effects.applyAll(c.effects(), ctx);
        if (c.response() != null && !c.response().isBlank()) {
            ctx.getIo().write(c.response());
        }
    }

    private static boolean present(GameContext ctx, String id) {
        return ctx.getPlayer().hasItem(id)
                || ctx.getPlayer().getCurrentRoom().findItem(id).isPresent();
    }

    private static void removeFromAnywhere(GameContext ctx, String id) {
        if (ctx.getPlayer().removeItem(id).isEmpty()) {
            ctx.getPlayer().getCurrentRoom().removeItem(id);
        }
    }

    private static String noSuch(String id) {
        return "There is no '" + id + "' here or in your inventory.";
    }
}
