package com.shanebeestudios.skbee.elements.virtualfurnace.type;

import ch.njol.skript.classes.Changer;
import ch.njol.skript.classes.Serializer;
import ch.njol.util.coll.CollectionUtils;
import ch.njol.yggdrasil.Fields;
import com.shanebeestudios.skbee.SkBee;
import com.github.shanebeee.skr.Registration;
import com.shanebeestudios.skbee.api.util.SkriptUtils;
import com.shanebeestudios.vf.api.FurnaceManager;
import com.shanebeestudios.vf.api.machine.Furnace;
import com.shanebeestudios.vf.api.machine.Machine;
import com.shanebeestudios.vf.api.property.Properties;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.StreamCorruptedException;
import java.util.UUID;

public class Types {

    public static final FurnaceManager FURNACE_MANAGER = SkBee.getPlugin().getVirtualFurnaceAPI().getFurnaceManager();

    public static void register(Registration reg) {
        reg.newType(Machine.class, "machine")
            .user("machines?")
            .name("VirtualFurnace - Machine")
            .description("Represents a virtual machine. These machines tick on their own like a regular",
                "vanilla Minecraft furnace except they can be loaded from anywhere and don't rely on chunks.")
            .since("3.3.0")
            .parser(SkriptUtils.getDefaultParser())
            .changer(new Changer<>() {
                @Override
                @Nullable
                public Class<?>[] acceptChange(@NotNull ChangeMode changeMode) {
                    if (changeMode == ChangeMode.DELETE) return CollectionUtils.array();
                    return null;
                }

                @Override
                public void change(Machine[] machines, @Nullable Object[] objects, ChangeMode changeMode) {
                    if (changeMode != ChangeMode.DELETE) return;

                    for (Machine machine : machines) {
                        FURNACE_MANAGER.removeMachine(machine, false);
                    }
                    FURNACE_MANAGER.saveConfig();
                }
            })
            .serializer(new Serializer<>() {
                @Override
                public @NotNull Fields serialize(Machine machine) {
                    Fields fields = new Fields();

                    // Might add new machines in the future
                    if (machine instanceof Furnace furnace) {
                        fields.putObject("type", "furnace");
                    }
                    fields.putObject("id", machine.getUniqueID().toString());
                    return fields;
                }

                @Override
                public void deserialize(Machine o, Fields f) {
                }

                @Override
                protected Machine deserialize(Fields fields) throws StreamCorruptedException {
                    String type = fields.getObject("type", String.class);
                    assert type != null;
                    if (type.equals("furnace")) {
                        String uuid = fields.getObject("id", String.class);
                        assert uuid != null;
                        Machine machine = FURNACE_MANAGER.getByID(UUID.fromString(uuid));
                        if (machine != null) return machine;
                        throw new StreamCorruptedException("Invalid machine with id: " + uuid);
                    }
                    throw new StreamCorruptedException("Invalid machine type: " + type);
                }

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

                @Override
                protected boolean canBeInstantiated() {
                    return false;
                }
            })
            .register();

        reg.newType(Properties.class, "machineproperty")
            .user("machine ?propert(y|ies)")
            .name("VirtualFurnace - Machine Properties")
            .description("Represents the machine properties of a virtual machine.")
            .since("3.3.0")
            .parser(SkriptUtils.getDefaultParser())
            .register();
    }

}
