package de.ellpeck.prettypipes.misc;

import de.ellpeck.prettypipes.PrettyPipes;
import de.ellpeck.prettypipes.packets.PacketButton;
import de.ellpeck.prettypipes.pipe.PipeBlockEntity;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.gui.widget.ExtendedButton;
import org.apache.commons.lang3.ArrayUtils;

public class DirectionSelector {

    private static final Direction[] ALL = ArrayUtils.addAll(Direction.values(), (Direction) null);

    // null means old behavior, which is all directions
    private Direction direction;
    private boolean modified;

    private final ItemStack stack;
    private final PipeBlockEntity pipe;

    public DirectionSelector(ItemStack stack, PipeBlockEntity pipe) {
        this.stack = stack;
        this.pipe = pipe;
        this.load();
    }

    @OnlyIn(Dist.CLIENT)
    public AbstractWidget getButton(int x, int y) {
        return new ExtendedButton(x, y, 100, 20, Component.translatable("info." + PrettyPipes.ID + ".populate"), button ->
                PacketButton.sendAndExecute(this.pipe.getBlockPos(), PacketButton.ButtonResult.DIRECTION_SELECTOR)) {
            @Override
            public Component getMessage() {
                var pipe = DirectionSelector.this.pipe;
                var dir = DirectionSelector.this.direction;
                var msg = Component.translatable("dir." + PrettyPipes.ID + "." + (dir != null ? dir.getName() : "all"));
                if (dir != null) {
                    var blockName = pipe.getItemHandler(dir) != null ? pipe.getLevel().getBlockState(pipe.getBlockPos().relative(dir)).getBlock().getName() : null;
                    if (blockName != null)
                        msg = msg.append(" (").append(blockName).append(")");
                }
                return msg;
            }
        };
    }

    public void onButtonPacket() {
        var dir = this.direction;
        do {
            dir = DirectionSelector.ALL[(ArrayUtils.indexOf(DirectionSelector.ALL, dir) + 1) % DirectionSelector.ALL.length];
        } while (!this.isDirectionValid(dir));
        if (this.direction != dir) {
            this.direction = dir;
            this.modified = true;
        }
    }

    public void save() {
        if (!this.modified)
            return;
        this.modified = false;

        var tag = new CompoundTag();
        if (this.direction != null)
            tag.putString("direction", this.direction.getName());
        this.stack.getOrCreateTag().put("direction_selector", tag);
    }

    public void load() {
        if (this.stack.hasTag()) {
            var tag = this.stack.getTag().getCompound("direction_selector");
            this.direction = Direction.byName(tag.getString("direction"));
        }
    }

    public Direction[] directions() {
        return this.direction != null ? new Direction[]{this.direction} : Direction.values();
    }

    public boolean has(Direction dir) {
        return this.direction == null || this.direction == dir;
    }

    private boolean isDirectionValid(Direction dir) {
        if (dir == null)
            return true;
        if (this.pipe.getItemHandler(dir) == null)
            return false;
        return this.pipe.streamModules()
                .filter(p -> p.getLeft() != this.stack)
                .map(p -> p.getRight().getDirectionSelector(p.getLeft(), this.pipe))
                .noneMatch(p -> p != null && p.direction == dir);
    }

    public interface IDirectionContainer {

        DirectionSelector getSelector();

    }
}
