package com.r3944realms.leashedplayer.mixin.both;

import com.mojang.serialization.Codec;
import com.r3944realms.leashedplayer.modInterface.IEntityLeadExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Leashable;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.util.Optional;



@Mixin(Entity.class)

public abstract class MixinEntity implements IEntityLeadExtension {
    @Unique int Pl$LeashKeepTick;//保存状态，当超过断裂绳长时若LeashKeepTick大于0，则不断裂
    @Unique float Pl$LeashLength;
    @Unique boolean Pl$isSync;
    @Shadow public abstract Level level();
    @SuppressWarnings("AddedMixinMembersNamePattern")
    @Override
    public float getLeashLength() {
        return Math.max(Pl$LeashLength, 6.0f);
    }
    @SuppressWarnings("AddedMixinMembersNamePattern")
    @Override
    public void setLeashLength(float length) {
        this.Pl$LeashLength = length;
    }

    @SuppressWarnings("AddedMixinMembersNamePattern")
    @Override
    public void setKeepLeashTick(int keepTick) {
        this.Pl$LeashKeepTick = Math.max(keepTick, 0);
    }
    @SuppressWarnings("AddedMixinMembersNamePattern")
    @Override
    public int getKeepLeashTick() {
        return this.Pl$LeashKeepTick;
    }

    /**
     * 这里重定向，当实体类实现了{@link PlayerLeashable}接口时，<br/>
     * 阻止原版的{@link Leashable}中 的tickLeash方法调用，将其<br/>
     * 我们需自己实现相关的逻辑
     * @param entity 实体
     * @param <E> 实体类型
     */
    @Redirect(
            method = "baseTick",
            at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Leashable;tickLeash(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/Entity;)V")
    )
    <E extends Entity & Leashable> void checkAndCancelIfTure(ServerLevel f, E entity) {
        if(!(entity instanceof PlayerLeashable) && level() instanceof ServerLevel serverLevel_) {
            Leashable.tickLeash(serverLevel_, entity);
        } else {
            PlayerLeashable.tickLeash(f, entity);
        }
    }
    @Inject(
            method = {"saveWithoutId"}, at = {@At("RETURN")}
    )//数据保存
    private void addSaveData(ValueOutput valueOutput, CallbackInfo ci) {
        valueOutput.putFloat("LeashLength", ((IEntityLeadExtension)this).getLeashLength());
    }
    @Inject(
            method = {"load"}, at = {@At("RETURN")}
    )//数据读取
    private void readSaveData(ValueInput valueInput, CallbackInfo ci) {
        Optional<Float> leashLength = valueInput.read("LeashLength", Codec.FLOAT);
        leashLength.ifPresent(i->((IEntityLeadExtension)this).setLeashLength(i));
        if(!this.level().isClientSide) ((IEntityLeadExtension)this).setLeadLengthSync(false);
    }

    @SuppressWarnings("AddedMixinMembersNamePattern")
    @Override
    public boolean hasLeadLengthSync() {
        return Pl$isSync;
    }

    @SuppressWarnings("AddedMixinMembersNamePattern")
    @Override
    public void setLeadLengthSync(boolean sync) {
        Pl$isSync = sync;
    }
}
