package top.r3944realms.lib39.mixin.callback;

import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.*;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import top.r3944realms.lib39.api.callback.AnvilUpdateCallback;

/**
 * The type Mixin anvil menu.
 */
@Mixin(AnvilMenu.class)
public abstract class MixinAnvilMenu extends AbstractContainerMenu {
    @Shadow
    private String itemName;
    @Final
    @Shadow private DataSlot cost;
    @Shadow
    private int repairItemCountCost;

    @Unique
    private Player cachedPlayer;

    /**
     * Instantiates a new Mixin anvil menu.
     *
     * @param menuType    the menu type
     * @param containerId the container id
     */
    protected MixinAnvilMenu(@Nullable MenuType<?> menuType, int containerId) {
        super(menuType, containerId);
    }

    /**
     * 捕获玩家引用
     */
    @Inject(method = "<init>(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/inventory/ContainerLevelAccess;)V",
            at = @At("RETURN"))
    private void onInit(int containerId, net.minecraft.world.entity.player.Inventory playerInventory,
                        ContainerLevelAccess access, CallbackInfo ci) {
        this.cachedPlayer = playerInventory.player;
    }

    /**
     * 在createResult方法开始时注入事件
     */
    @Inject(
            method = "createResult",
            at = @At(value = "HEAD"),
            cancellable = true
    )
    private void onAnvilUpdate(CallbackInfo ci) {
        AnvilMenu menu = AnvilMenu.class.cast(this);
        ItemStack left = menu.getSlot(0).getItem();
        ItemStack right = menu.getSlot(1).getItem();
        ItemStack outputSlot = menu.getSlot(2).getItem();

        // 如果左侧为空，不处理
        if (left.isEmpty()) {
            return;
        }

        // 调用事件
        AnvilUpdateCallback.AnvilUpdateResult result = AnvilUpdateCallback.EVENT.invoker()
                .onAnvilUpdate(left, right, outputSlot, itemName, cost.get(), cachedPlayer);

        if (result != null) {
            if (result.cancel()) {
                // 取消事件，清空输出
                menu.getSlot(2).set(ItemStack.EMPTY);
                cost.set(0);
                repairItemCountCost = 0;
                broadcastChanges();
                ci.cancel();
                return;
            }

            if (result.shouldOverride()) {
                // 设置自定义结果
                menu.getSlot(2).set(result.output());
                cost.set(result.cost());
                repairItemCountCost = result.materialCost();
                broadcastChanges();
                ci.cancel();
            }
        }
    }
}
