package com.tiedup.remake.entities;

import com.tiedup.remake.blocks.entity.KidnapBombBlockEntity;
import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.util.KidnapExplosion;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.MoverType;
import net.minecraft.world.entity.item.PrimedTnt;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;

/**
 * Kidnap Bomb Entity - Primed TNT that applies bondage on explosion.
 *
 *
 * When the fuse runs out, instead of a destructive explosion,
 * it applies stored bondage items to all entities in radius.
 *
 * Based on original EntityKidnapBomb from 1.12.2
 */
public class EntityKidnapBomb extends PrimedTnt {

    // Stored bondage items
    private ItemStack bind = ItemStack.EMPTY;
    private ItemStack gag = ItemStack.EMPTY;
    private ItemStack blindfold = ItemStack.EMPTY;
    private ItemStack earplugs = ItemStack.EMPTY;
    private ItemStack collar = ItemStack.EMPTY;
    private ItemStack clothes = ItemStack.EMPTY;

    public EntityKidnapBomb(
        EntityType<? extends EntityKidnapBomb> type,
        Level level
    ) {
        super(type, level);
    }

    /**
     * Create from a placed bomb block.
     */
    public EntityKidnapBomb(
        Level level,
        double x,
        double y,
        double z,
        @Nullable LivingEntity igniter,
        @Nullable KidnapBombBlockEntity bombTile
    ) {
        super(ModEntities.KIDNAP_BOMB_ENTITY.get(), level);
        this.setPos(x, y, z);
        double d0 = level.random.nextDouble() * (Math.PI * 2);
        this.setDeltaMovement(-Math.sin(d0) * 0.02, 0.2, -Math.cos(d0) * 0.02);
        this.setFuse(SettingsAccessor.getKidnapBombFuse());

        this.xo = x;
        this.yo = y;
        this.zo = z;

        // Copy bondage items from tile entity
        if (bombTile != null) {
            this.bind = bombTile.getBind().copy();
            this.gag = bombTile.getGag().copy();
            this.blindfold = bombTile.getBlindfold().copy();
            this.earplugs = bombTile.getEarplugs().copy();
            this.collar = bombTile.getCollar().copy();
            this.clothes = bombTile.getClothes().copy();
        }
    }

    @Override
    public void tick() {
        // Store previous position
        this.xo = this.getX();
        this.yo = this.getY();
        this.zo = this.getZ();

        // Apply gravity
        if (!this.isNoGravity()) {
            this.setDeltaMovement(this.getDeltaMovement().add(0, -0.04, 0));
        }

        // Move
        this.move(MoverType.SELF, this.getDeltaMovement());

        // Apply friction
        this.setDeltaMovement(this.getDeltaMovement().scale(0.98));

        if (this.onGround()) {
            this.setDeltaMovement(
                this.getDeltaMovement().multiply(0.7, -0.5, 0.7)
            );
        }

        // Handle fuse
        int fuse = this.getFuse() - 1;
        this.setFuse(fuse);

        if (fuse <= 0) {
            this.discard();
            if (!this.level().isClientSide) {
                this.explode();
            }
        } else {
            // Spawn smoke particles (client-side only)
            this.updateInWaterStateAndDoFluidPushing();
            if (this.level().isClientSide) {
                this.level().addParticle(
                    ParticleTypes.SMOKE,
                    this.getX(),
                    this.getY() + 0.5,
                    this.getZ(),
                    0,
                    0,
                    0
                );
            }
        }
    }

    /**
     * Perform the kidnap explosion (no block damage).
     */
    protected void explode() {
        int radius = getExplosionRadius();
        BlockPos pos = this.blockPosition();

        KidnapExplosion explosion = new KidnapExplosion(
            this.level(),
            pos,
            radius,
            bind,
            gag,
            blindfold,
            earplugs,
            collar,
            clothes
        );
        explosion.explode();
    }

    /**
     * Get the explosion radius from game rules.
     */
    private int getExplosionRadius() {
        // Default radius of 5 blocks
        return SettingsAccessor.getKidnapBombRadius(
            this.level().getGameRules()
        );
    }

    // NBT SERIALIZATION

    @Override
    protected void addAdditionalSaveData(CompoundTag tag) {
        super.addAdditionalSaveData(tag);

        if (!bind.isEmpty()) {
            tag.put("bind", bind.save(new CompoundTag()));
        }
        if (!gag.isEmpty()) {
            tag.put("gag", gag.save(new CompoundTag()));
        }
        if (!blindfold.isEmpty()) {
            tag.put("blindfold", blindfold.save(new CompoundTag()));
        }
        if (!earplugs.isEmpty()) {
            tag.put("earplugs", earplugs.save(new CompoundTag()));
        }
        if (!collar.isEmpty()) {
            tag.put("collar", collar.save(new CompoundTag()));
        }
        if (!clothes.isEmpty()) {
            tag.put("clothes", clothes.save(new CompoundTag()));
        }
    }

    @Override
    protected void readAdditionalSaveData(CompoundTag tag) {
        super.readAdditionalSaveData(tag);

        if (tag.contains("bind")) {
            bind = ItemStack.of(tag.getCompound("bind"));
        }
        if (tag.contains("gag")) {
            gag = ItemStack.of(tag.getCompound("gag"));
        }
        if (tag.contains("blindfold")) {
            blindfold = ItemStack.of(tag.getCompound("blindfold"));
        }
        if (tag.contains("earplugs")) {
            earplugs = ItemStack.of(tag.getCompound("earplugs"));
        }
        if (tag.contains("collar")) {
            collar = ItemStack.of(tag.getCompound("collar"));
        }
        if (tag.contains("clothes")) {
            clothes = ItemStack.of(tag.getCompound("clothes"));
        }
    }
}
