package com.tiedup.remake.entities;

import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.Level;

/**
 * Lightweight fishing bobber entity spawned by NPCs during the FISH command.
 *
 * <p>Floats on the water surface with a sinusoidal bob animation.
 * After a random delay, triggers a bite event (splash particles + sound).
 * The owning NPC's goal checks {@link #isBiting()} each tick and reels in
 * when a bite is detected.</p>
 *
 * <p>Ephemeral entity: no NBT persistence. Auto-discards after {@value #MAX_LIFE} ticks.</p>
 */
public class NpcFishingBobber extends Entity {

    private static final EntityDataAccessor<Integer> DATA_OWNER_ID =
        SynchedEntityData.defineId(
            NpcFishingBobber.class,
            EntityDataSerializers.INT
        );

    private static final EntityDataAccessor<Boolean> DATA_BITING =
        SynchedEntityData.defineId(
            NpcFishingBobber.class,
            EntityDataSerializers.BOOLEAN
        );

    /** Safety removal after 30 seconds */
    private static final int MAX_LIFE = 600;

    /** Minimum ticks before a bite can occur */
    private static final int MIN_BITE_TIME = 100;

    /** Maximum ticks before a bite can occur */
    private static final int MAX_BITE_TIME = 300;

    private int biteTimer;
    private int lifeTimer;

    /**
     * Registration constructor.
     */
    public NpcFishingBobber(EntityType<?> type, Level level) {
        super(type, level);
    }

    /**
     * Factory method: creates a bobber at the surface of the given water block.
     *
     * @param level    The server level
     * @param owner    The NPC that owns this bobber
     * @param waterPos The water block position (bobber sits on top)
     * @return A new NpcFishingBobber positioned at the water surface
     */
    public static NpcFishingBobber create(
        Level level,
        EntityDamsel owner,
        BlockPos waterPos
    ) {
        NpcFishingBobber bobber = new NpcFishingBobber(
            ModEntities.NPC_FISHING_BOBBER.get(),
            level
        );
        bobber.setPos(
            waterPos.getX() + 0.5,
            waterPos.getY() + 1.0, // surface of water
            waterPos.getZ() + 0.5
        );
        bobber.entityData.set(DATA_OWNER_ID, owner.getId());
        bobber.biteTimer =
            MIN_BITE_TIME +
            owner.getRandom().nextInt(MAX_BITE_TIME - MIN_BITE_TIME);
        return bobber;
    }

    @Override
    protected void defineSynchedData() {
        this.entityData.define(DATA_OWNER_ID, 0);
        this.entityData.define(DATA_BITING, false);
    }

    @Override
    protected void readAdditionalSaveData(CompoundTag tag) {
        // Ephemeral entity - no persistence
    }

    @Override
    protected void addAdditionalSaveData(CompoundTag tag) {
        // Ephemeral entity - no persistence
    }

    @Override
    public void tick() {
        super.tick();

        lifeTimer++;
        if (lifeTimer >= MAX_LIFE) {
            discard();
            return;
        }

        // Sinusoidal bob on water surface
        setDeltaMovement(0, Math.sin(tickCount * 0.15) * 0.01, 0);

        // Server-side bite logic
        if (!level().isClientSide && !isBiting()) {
            biteTimer--;
            if (biteTimer <= 0) {
                setBiting(true);

                // Splash particles
                if (level() instanceof ServerLevel serverLevel) {
                    serverLevel.sendParticles(
                        ParticleTypes.FISHING,
                        getX(),
                        getY(),
                        getZ(),
                        5, // count
                        0.1,
                        0.0,
                        0.1, // spread
                        0.02 // speed
                    );
                }

                // Splash sound
                level().playSound(
                    null,
                    getX(),
                    getY(),
                    getZ(),
                    SoundEvents.FISHING_BOBBER_SPLASH,
                    SoundSource.NEUTRAL,
                    1.0f,
                    1.0f
                );
            }
        }
    }

    /**
     * Get the NPC that owns this bobber.
     *
     * @return The owner EntityDamsel, or null if not found
     */
    public EntityDamsel getOwnerNpc() {
        Entity entity = level().getEntity(entityData.get(DATA_OWNER_ID));
        return entity instanceof EntityDamsel damsel ? damsel : null;
    }

    /**
     * Whether a fish is biting this bobber.
     */
    public boolean isBiting() {
        return entityData.get(DATA_BITING);
    }

    /**
     * Set the biting state.
     */
    public void setBiting(boolean biting) {
        entityData.set(DATA_BITING, biting);
    }

    @Override
    public boolean isPickable() {
        return false;
    }

    @Override
    public Packet<ClientGamePacketListener> getAddEntityPacket() {
        return new ClientboundAddEntityPacket(this);
    }
}
