package sh.grimmer.bettershulkers.mixin;

import net.minecraft.core.NonNullList;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.inventory.tooltip.TooltipComponent;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.ItemContainerContents;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.ShulkerBoxBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity;
import net.minecraft.core.component.DataComponents;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import sh.grimmer.bettershulkers.BetterShulkers;
import sh.grimmer.bettershulkers.config.TooltipPreviewMode;
import sh.grimmer.bettershulkers.tooltip.ContainerTooltip;
import sh.grimmer.bettershulkers.util.ShulkerBoxHelper;

import java.util.Optional;

@Mixin(BlockItem.class)
public abstract class BlockItemMixin extends Item {

    @Shadow
    @Final
    private Block block;

    public BlockItemMixin(Properties properties) {
        super(properties);
    }

    @Override
    public Optional<TooltipComponent> getTooltipImage(ItemStack stack) {
        if (block instanceof ShulkerBoxBlock && BetterShulkers.CONFIG.tooltipPreview != TooltipPreviewMode.NEVER) {
            ItemContainerContents contents = stack.getOrDefault(DataComponents.CONTAINER, ItemContainerContents.EMPTY);
            if (BetterShulkers.CONFIG.tooltipPreview == TooltipPreviewMode.WHEN_FILLED && contents.stream().allMatch(ItemStack::isEmpty)) {
                return super.getTooltipImage(stack);
            }
            NonNullList<ItemStack> items = NonNullList.withSize(27, ItemStack.EMPTY);
            contents.copyInto(items);
            return Optional.of(new ContainerTooltip(9, 3, items));
        }
        return super.getTooltipImage(stack);
    }

    @Override
    public boolean isBarVisible(ItemStack stack) {
        if (BetterShulkers.CONFIG.showFillBar && block instanceof ShulkerBoxBlock) {
            NonNullList<ItemStack> items = ShulkerBoxHelper.getItems(stack);
            return items.stream().anyMatch(s -> !s.isEmpty());
        }
        return super.isBarVisible(stack);
    }

    @Override
    public int getBarWidth(ItemStack stack) {
        if (BetterShulkers.CONFIG.showFillBar && block instanceof ShulkerBoxBlock) {
            NonNullList<ItemStack> items = ShulkerBoxHelper.getItems(stack);
            long occupied = items.stream().filter(s -> !s.isEmpty()).count();
            return Math.round((float) occupied / (float) items.size() * 13.0F);
        }
        return super.getBarWidth(stack);
    }

    @Override
    public int getBarColor(ItemStack stack) {
        if (BetterShulkers.CONFIG.showFillBar && block instanceof ShulkerBoxBlock) {
            NonNullList<ItemStack> items = ShulkerBoxHelper.getItems(stack);
            long occupied = items.stream().filter(s -> !s.isEmpty()).count();
            float fraction = (float) occupied / (float) items.size();
            return Mth.hsvToRgb((1.0F - fraction) / 3.0F, 1.0F, 1.0F);
        }
        return super.getBarColor(stack);
    }

    @Inject(method = "place", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;gameEvent(Lnet/minecraft/core/Holder;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/gameevent/GameEvent$Context;)V", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD)
    private void onPlace(BlockPlaceContext ctx, CallbackInfoReturnable<InteractionResult> cir, BlockPlaceContext actualCtx) {
        if (!BetterShulkers.CONFIG.showBlockHint) {
            return;
        }
        Level level = actualCtx.getLevel();
        if (!level.isClientSide()) {
            return;
        }
        BlockEntity be = level.getBlockEntity(actualCtx.getClickedPos());
        if (!(be instanceof ShulkerBoxBlockEntity shulkerBe)) {
            return;
        }
        ItemStack item = actualCtx.getItemInHand();
        if (!ShulkerBoxHelper.isShulkerBox(item)) {
            return;
        }
        shulkerBe.applyComponentsFromItemStack(item);
    }
}
