package pokefenn.totemic.tile.totem;

import javax.annotation.Nullable;

import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.EndTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import pokefenn.totemic.Totemic;
import pokefenn.totemic.api.TotemicAPI;
import pokefenn.totemic.api.ceremony.Ceremony;
import pokefenn.totemic.api.ceremony.CeremonyInstance;
import pokefenn.totemic.api.ceremony.StartupContext;
import pokefenn.totemic.api.music.DefaultMusicAcceptor;
import pokefenn.totemic.api.music.MusicAcceptor;
import pokefenn.totemic.api.music.MusicInstrument;
import pokefenn.totemic.network.ClientboundPacketStartupMusic;
import pokefenn.totemic.network.NetworkHandler;

public final class StateStartup extends TotemState implements StartupContext {
    static final byte ID = 2;

    private Ceremony ceremony;
    private CeremonyInstance instance;
    private Entity initiator;

    private final DefaultMusicAcceptor musicHandler = new DefaultMusicAcceptor();
    private int time = 0;

    StateStartup(TileTotemBase tile, Ceremony ceremony, CeremonyInstance instance, Entity initiator) {
        super(tile);
        this.ceremony = ceremony;
        this.instance = instance;
        this.initiator = initiator;
    }

    StateStartup(TileTotemBase tile) {
        super(tile);
    }

    @Override
    public boolean canAcceptMusic(MusicInstrument instr) {
        return musicHandler.canAcceptMusic(instr);
    }

    @Override
    public boolean acceptMusic(MusicInstrument instr, int amount, double x, double y, double z, @Nullable Entity entity) {
        if(musicHandler.acceptMusic(instr, amount, x, y, z, entity)) {
            NetworkHandler.channel.send(NetworkHandler.nearTile(tile, 16),
                    new ClientboundPacketStartupMusic(tile.getBlockPos(), instr, musicHandler.getMusicAmount(instr)));
            tile.setChanged();
            return true;
        }
        else
            return false;
    }

    @Override
    public int getPriority() {
        return MusicAcceptor.CEREMONY_PRIORITY;
    }

    @Override
    public void tick() {
        Level world = tile.getLevel();
        BlockPos pos = tile.getBlockPos();

        if(!world.isClientSide) {
            if(musicHandler.getTotalMusic() >= ceremony.getMusicNeeded()) {
                if(instance.canStartEffect(world, pos, this))
                    startCeremony();
                else
                    failCeremony();
            }
            else if(time >= ceremony.getAdjustedMaxStartupTime(world.getDifficulty())) {
                instance.onStartupFail(world, pos, this);
                failCeremony();
            }
            else {
                instance.onStartup(world, pos, this);


            }
        }
        else
            instance.onStartup(world, pos, this); //do not change state based on time on the client side (to account for TPS lag)

        time++;
    }

    @Override
    public int getTime() {
        return time;
    }

    @Override
    public int getTotalMusic() {
        return musicHandler.getTotalMusic();
    }

    @Override
    public int getMusic(MusicInstrument instrument) {
        return musicHandler.getMusicAmount(instrument);
    }

    public void setMusic(MusicInstrument instrument, int amount) {
        musicHandler.setMusicAmount(instrument, amount);
    }

    @Override
    public Entity getInitiator() {
        return initiator;
    }

    @Override
    public void failCeremony() {
        tile.setTotemState(new StateTotemEffect(tile));
    }

    @Override
    public void startCeremony() {
        tile.setTotemState(new StateCeremonyEffect(tile, ceremony, instance, initiator));
    }

    public Ceremony getCeremony() {
        return ceremony;
    }

    public CeremonyInstance getCeremonyInstance() {
        return instance;
    }

    @Override
    byte getID() {
        return ID;
    }

    @Override
    void save(CompoundTag tag) {
        tag.putString("Ceremony", ceremony.getRegistryName().toString());
        Tag instanceData = instance.serializeNBT();
        if(instanceData != EndTag.INSTANCE)
            tag.put("InstanceData", instanceData);
        tag.put("Music", musicHandler.serializeNBT());
        tag.putInt("Time", time);
        //TODO: Save initiator as well? Do we need the initiator?
    }

    @Override
    void load(CompoundTag tag) {
        var ceremonyName = new ResourceLocation(tag.getString("Ceremony"));
        ceremony = TotemicAPI.get().registry().ceremonies().get(ceremonyName);
        if(ceremony == null) {
            Totemic.logger.error("Unknown Ceremony: {}", ceremonyName);
            tile.setTotemState(new StateTotemEffect(tile));
            return;
        }
        instance = ceremony.createInstance();
        if(tag.contains("InstanceData"))
            instance.deserializeNBT(tag.get("InstanceData"));
        musicHandler.deserializeNBT(tag.getCompound("Music"));
        time = tag.getInt("Time");
    }
}

@@ -102,16 +102,67 @@
 ockPos;%0A
+import net.minecraft.core.particles.ParticleTypes;%0A
 import n
@@ -879,16 +879,55 @@
 Handler;
+%0Aimport pokefenn.totemic.util.MiscUtil;
 %0A%0Apublic
@@ -3719,110 +3719,317 @@
     
-tile.setTotemState(new StateTotemEffect(tile));%0A    %7D%0A%0A    @Override%0A    public void startCeremony() %7B
+MiscUtil.spawnServerParticles(ParticleTypes.LARGE_SMOKE, tile.getLevel(), getPosition(), 16);%0A        tile.setTotemState(new StateTotemEffect(tile));%0A    %7D%0A%0A    @Override%0A    public void startCeremony() %7B%0A        MiscUtil.spawnServerParticles(ParticleTypes.HAPPY_VILLAGER, tile.getLevel(), getPosition(), 16);
 %0A   

Add particles on completion/failure of ceremony