/*
 * Decompiled with CFR 0.152.
 * 
 * Could not load the following classes:
 *  net.minecraft.class_1277
 *  net.minecraft.class_1661
 *  net.minecraft.class_1735
 *  net.minecraft.class_1799
 *  net.minecraft.class_1935
 *  net.minecraft.class_3545
 *  net.minecraft.class_465
 *  net.minecraft.class_476
 *  net.minecraft.class_481
 *  net.minecraft.class_495
 *  net.minecraft.class_7923
 */
package meteordevelopment.meteorclient.utils.player;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import meteordevelopment.meteorclient.mixininterface.ISlot;
import meteordevelopment.meteorclient.utils.player.InvUtils;
import meteordevelopment.meteorclient.utils.player.SlotUtils;
import meteordevelopment.meteorclient.utils.render.PeekScreen;
import net.minecraft.class_1277;
import net.minecraft.class_1661;
import net.minecraft.class_1735;
import net.minecraft.class_1799;
import net.minecraft.class_1935;
import net.minecraft.class_3545;
import net.minecraft.class_465;
import net.minecraft.class_476;
import net.minecraft.class_481;
import net.minecraft.class_495;
import net.minecraft.class_7923;

public class InventorySorter {
    private final class_465<?> screen;
    private final InvPart originInvPart;
    private boolean invalid;
    private List<Action> actions;
    private int timer;
    private int currentActionI;

    public InventorySorter(class_465<?> screen, class_1735 originSlot) {
        this.screen = screen;
        this.originInvPart = this.getInvPart(originSlot);
        if (this.originInvPart == InvPart.Invalid || this.originInvPart == InvPart.Hotbar || screen instanceof PeekScreen) {
            this.invalid = true;
            return;
        }
        this.actions = new ArrayList<Action>();
        this.generateActions();
    }

    public boolean tick(int delay) {
        if (this.invalid) {
            return true;
        }
        if (this.currentActionI >= this.actions.size()) {
            return true;
        }
        if (this.timer < delay) {
            ++this.timer;
            return false;
        }
        this.timer = 0;
        Action action = this.actions.get(this.currentActionI);
        InvUtils.move().fromId(action.from).toId(action.to);
        ++this.currentActionI;
        return false;
    }

    private void generateActions() {
        ArrayList<MySlot> slots = new ArrayList<MySlot>();
        for (class_1735 slot : this.screen.method_17577().field_7761) {
            if (this.getInvPart(slot) != this.originInvPart) continue;
            slots.add(new MySlot(((ISlot)slot).meteor$getId(), slot.method_7677()));
        }
        slots.sort(Comparator.comparingInt(value -> value.id));
        this.generateStackingActions(slots);
        this.generateSortingActions(slots);
    }

    private void generateStackingActions(List<MySlot> slots) {
        SlotMap slotMap = new SlotMap();
        for (MySlot mySlot : slots) {
            if (mySlot.itemStack.method_7960() || !mySlot.itemStack.method_7946() || mySlot.itemStack.method_7947() >= mySlot.itemStack.method_7914()) continue;
            slotMap.get(mySlot.itemStack).add(mySlot);
        }
        for (class_3545 class_35452 : slotMap.map) {
            List slotsToStack = (List)class_35452.method_15441();
            MySlot slotToStackTo = null;
            for (int i = 0; i < slotsToStack.size(); ++i) {
                MySlot slot = (MySlot)slotsToStack.get(i);
                if (slotToStackTo == null) {
                    slotToStackTo = slot;
                    continue;
                }
                this.actions.add(new Action(slot.id, slotToStackTo.id));
                if (slotToStackTo.itemStack.method_7947() + slot.itemStack.method_7947() <= slotToStackTo.itemStack.method_7914()) {
                    slotToStackTo.itemStack = new class_1799((class_1935)slotToStackTo.itemStack.method_7909(), slotToStackTo.itemStack.method_7947() + slot.itemStack.method_7947());
                    slot.itemStack = class_1799.field_8037;
                    if (slotToStackTo.itemStack.method_7947() < slotToStackTo.itemStack.method_7914()) continue;
                    slotToStackTo = null;
                    continue;
                }
                int needed = slotToStackTo.itemStack.method_7914() - slotToStackTo.itemStack.method_7947();
                slotToStackTo.itemStack = new class_1799((class_1935)slotToStackTo.itemStack.method_7909(), slotToStackTo.itemStack.method_7914());
                slot.itemStack = new class_1799((class_1935)slot.itemStack.method_7909(), slot.itemStack.method_7947() - needed);
                slotToStackTo = null;
                --i;
            }
        }
    }

    private void generateSortingActions(List<MySlot> slots) {
        for (int i = 0; i < slots.size(); ++i) {
            MySlot bestSlot = null;
            for (int j = i; j < slots.size(); ++j) {
                MySlot slot = slots.get(j);
                if (bestSlot == null) {
                    bestSlot = slot;
                    continue;
                }
                if (!this.isSlotBetter(bestSlot, slot)) continue;
                bestSlot = slot;
            }
            if (bestSlot.itemStack.method_7960()) continue;
            MySlot toSlot = slots.get(i);
            int from = bestSlot.id;
            int to = toSlot.id;
            if (from == to) continue;
            class_1799 temp = bestSlot.itemStack;
            bestSlot.itemStack = toSlot.itemStack;
            toSlot.itemStack = temp;
            this.actions.add(new Action(from, to));
        }
    }

    private boolean isSlotBetter(MySlot best, MySlot slot) {
        class_1799 bestI = best.itemStack;
        class_1799 slotI = slot.itemStack;
        if (bestI.method_7960() && !slotI.method_7960()) {
            return true;
        }
        if (!bestI.method_7960() && slotI.method_7960()) {
            return false;
        }
        int c = class_7923.field_41178.method_10221((Object)bestI.method_7909()).method_12833(class_7923.field_41178.method_10221((Object)slotI.method_7909()));
        if (c == 0) {
            if (slotI.method_7947() != bestI.method_7947()) {
                return slotI.method_7947() > bestI.method_7947();
            }
            if (slotI.method_7919() != bestI.method_7919()) {
                return slotI.method_7919() > bestI.method_7919();
            }
        }
        return c > 0;
    }

    private InvPart getInvPart(class_1735 slot) {
        int i = ((ISlot)slot).meteor$getIndex();
        if (slot.field_7871 instanceof class_1661 && (!(this.screen instanceof class_481) || ((ISlot)slot).meteor$getId() > 8)) {
            if (SlotUtils.isHotbar(i)) {
                return InvPart.Hotbar;
            }
            if (SlotUtils.isMain(i)) {
                return InvPart.Player;
            }
        } else if ((this.screen instanceof class_476 || this.screen instanceof class_495) && slot.field_7871 instanceof class_1277) {
            return InvPart.Main;
        }
        return InvPart.Invalid;
    }

    private static enum InvPart {
        Hotbar,
        Player,
        Main,
        Invalid;

    }

    private record Action(int from, int to) {
    }

    private static class MySlot {
        public final int id;
        public class_1799 itemStack;

        public MySlot(int id, class_1799 itemStack) {
            this.id = id;
            this.itemStack = itemStack;
        }
    }

    private static class SlotMap {
        private final List<class_3545<class_1799, List<MySlot>>> map = new ArrayList<class_3545<class_1799, List<MySlot>>>();

        private SlotMap() {
        }

        public List<MySlot> get(class_1799 itemStack) {
            for (class_3545<class_1799, List<MySlot>> entry : this.map) {
                if (!class_1799.method_31577((class_1799)itemStack, (class_1799)((class_1799)entry.method_15442()))) continue;
                return (List)entry.method_15441();
            }
            ArrayList<MySlot> list = new ArrayList<MySlot>();
            this.map.add((class_3545<class_1799, List<MySlot>>)new class_3545((Object)itemStack, list));
            return list;
        }
    }
}

