package com.thebrokenrail.twine.mixin;

import com.thebrokenrail.twine.Twine;
import com.thebrokenrail.twine.component.StageDataComponent;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
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;

@Mixin(ServerPlayerEntity.class)
public abstract class MixinServerPlayerEntity {
    @Shadow
    public abstract ServerWorld getServerWorld();

    @Unique
    private long lastTime = -1L;

    @Inject(at = @At("RETURN"), method = "tick")
    public void tick(CallbackInfo info) {
        StageDataComponent component = StageDataComponent.getFromWorld(getServerWorld());
        StageDataComponent.StageData[] data = component.getData(((ServerPlayerEntity) (Object) this).getUuid());
        int stage = StageDataComponent.findPersonalStageOfChunk(((ServerPlayerEntity) (Object) this).getBlockPos(), data);
        StageDataComponent.StageData stageObj = data[stage];
        if (stage + 1 < Twine.STAGE_COUNT) {
            if (lastTime != -1L) {
                stageObj.time = stageObj.time + Math.max(0, getServerWorld().getTime() - lastTime);
            }
            if (stageObj.time >= Twine.STAGE_TIME) {
                StageDataComponent.StageData old = data[stage + 1];
                if (old != null) {
                    old.time = 0;
                }
                StageDataComponent.StageData newData = new StageDataComponent.StageData();
                BlockPos pos = ((ServerPlayerEntity) (Object) this).getBlockPos();
                newData.x = pos.getX();
                newData.z = pos.getZ();
                data[stage + 1] = newData;
                data[stage] = old;
            }
        }
        lastTime = getServerWorld().getTime();
        component.markDirty();
    }
}
