package net.pietru.omni_power.ui;

import com.badlogic.gdx.scenes.scene2d.Action;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable;
import com.badlogic.gdx.utils.JsonValue;
import finalforeach.cosmicreach.blockevents.BlockEventArgs;
import finalforeach.cosmicreach.blockevents.BlockEventTrigger;
import finalforeach.cosmicreach.blocks.BlockPosition;
import finalforeach.cosmicreach.blocks.BlockState;
import finalforeach.cosmicreach.gamestates.InGame;
import finalforeach.cosmicreach.items.ISlotContainerParent;
import finalforeach.cosmicreach.items.ItemSlot;
import finalforeach.cosmicreach.items.containers.SlotContainer;
import finalforeach.cosmicreach.items.screens.BaseItemScreen;
import finalforeach.cosmicreach.savelib.utils.TriConsumer;
import finalforeach.cosmicreach.ui.GameStyles;
import finalforeach.cosmicreach.ui.UI;
import finalforeach.cosmicreach.ui.widgets.ItemSlotWidget;
import finalforeach.cosmicreach.world.Zone;
import net.pietru.omni_power.OmniPower;
import net.pietru.omni_power.blocks.CustomUIBlockEntity;

import java.util.HashMap;
import java.util.Map;

public class CustomScreen extends BaseItemScreen {
    public static final Map<String,TriConsumer<Table, CustomScreen,JsonValue>> components = new HashMap<>();
    public static final Map<String,TriConsumer<TextButtonWidget, CustomScreen,JsonValue>> button_events = new HashMap<>();

    SlotContainer container;

    public CustomScreen(ISlotContainerParent parent, final String ui_id) {
        super(parent);

        if (!OmniPower.uis.containsKey(ui_id)) {
            System.out.println("Omni Power [ERROR] Tried accessing/opening non existent ui data.");
            return;
        }

        JsonValue dataJson = OmniPower.uis.get(ui_id);
        JsonValue ui_layout = dataJson.get("layout");


        if (parent instanceof CustomUIBlockEntity)
            container=((CustomUIBlockEntity) parent).slotContainer;
        else if (parent instanceof DummyObject)
            container=((DummyObject) parent).container;

        Stack stack = new Stack();
        Actor background = new Image(GameStyles.containerBackground9Patch);

        this.slotWidgets = new ItemSlotWidget[container.getNumSlots()];

        Table table = new Table();
        build_ui(ui_layout,table,this);

        for (int i = 0; i<slotWidgets.length;i++){
            if (slotWidgets[i]==null)
                slotWidgets[i]=new ItemSlotWidget(parent,container,i);
        }


        background.setWidth(ui_layout.getFloat("width",250));
        background.setHeight(ui_layout.getFloat("height",200));

        stack.add(background);
        stack.add(table);
        stack.setBounds(background.getX(), background.getY(), background.getWidth(), background.getHeight());
        this.slotActor = stack;
        stack.setHeight(stack.getHeight() + 16.0F);
        this.init();
    }

    static void build_ui(JsonValue layout,Table table, CustomScreen screen){
        for (JsonValue data : layout) {
            String type = data.getString("type", "");
            if (type.isEmpty())
                continue;
            if (!components.containsKey(type.toLowerCase()))
                continue;
            TriConsumer<Table, CustomScreen, JsonValue> component = components.get(type.toLowerCase());
            component.accept(table, screen, data);
        }
    }

    static void add_ui_slot(Table table, CustomScreen screen, int n, boolean is_output){
        ItemSlot slot = screen.container.getSlot(n);
        slot.setOutputOnly(is_output);
        ItemSlotWidget slotWidget;
        if (slot.isOutputOnly())
            slotWidget = new ItemSlotWidget(screen.parent, screen.container, slot.getSlotId(),
                    new NinePatchDrawable(GameStyles.containerOutput9Patch),
                    new NinePatchDrawable(GameStyles.containerOutput9PatchHovered),
                    new NinePatchDrawable(GameStyles.containerSelected9Patch)
            );
        else
            slotWidget = new ItemSlotWidget(screen.parent,screen.container, slot.getSlotId());
        screen.slotWidgets[n] = slotWidget;
        table.add(slotWidget);
    }



    public static void addOpenContainer(final ISlotContainerParent be, final SlotContainer container){
        String ui_id = "";
        if (be instanceof CustomUIBlockEntity)
            ui_id=((CustomUIBlockEntity) be).ui_id;
        else if (be instanceof DummyObject)
            ui_id= ((DummyObject) be).ui_id;
        addOpenContainer(be,container,ui_id);
    }
    public static void addOpenContainer(final ISlotContainerParent be, final SlotContainer container, final String ui_id) {
        if (!UI.openContainers.contains(container, true)) {
            UI.itemCatalog.show();
            UI.openContainers.add(container);
            final CustomScreen screen = new CustomScreen(be, ui_id);
            InGame.IN_GAME.openedMainItemScreen = screen;
            InGame.IN_GAME.addBaseItemScreen(screen);
            Action perFrameAct = new Action() {
                public boolean act(float delta) {
                    screen.getActor().setX(InGame.IN_GAME.newUiViewport.getWorldWidth() / 2.0F, 1);
                    screen.getActor().setY(InGame.IN_GAME.newUiViewport.getWorldHeight() / 2.0F, 1);
                    if (!UI.isInventoryOpen()) {
                        UI.openContainers.removeValue(container, true);
                        InGame.IN_GAME.removeBaseItemScreen(screen);
                        return true;
                    } else {
                        return false;
                    }
                }
            };
            perFrameAct.act(0.0F);
            screen.getActor().addAction(perFrameAct);
        }
    }

    public static void load_base_button_events(){
        button_events.put("change_ui",(button,screen,data)->{
            String ui_id = data.getString("gui_id","");
            button.addListener(event -> {
                if (!button.isPressed())
                    return false;
                UI.openContainers.removeValue(screen.container, true);
                InGame.IN_GAME.removeBaseItemScreen(screen);
                addOpenContainer(screen.parent,screen.container,ui_id);
                return true;
            });
        });
        button_events.put("run_trigger",(button,screen,data)->{
            String trigger_id = data.getString("trigger_id","");
            button.addListener(event -> {
                if (!button.isPressed())
                    return false;
                if (screen.parent instanceof DummyObject)
                    runTrigger(trigger_id,((DummyObject) screen.parent).blockPos, (BlockEventArgs) screen.parent);
                return true;
            });
        });
        button_events.put("close_ui",(button,screen,data)->{
            button.addListener(event -> {
                if (!button.isPressed())
                    return false;
                UI.openContainers.removeValue(screen.container, true);
                InGame.IN_GAME.removeBaseItemScreen(screen);
                return true;
            });
        });
    }

    private static void runTrigger(String triggerId, BlockPosition triggerPos, BlockEventArgs args) {

        Zone zone = args.zone;
        if (triggerPos != null) {
            BlockState targetBlockState = triggerPos.getBlockState();
            if (targetBlockState == null) {
                return;
            }

            BlockEventTrigger[] customTrigger = targetBlockState.getTrigger(triggerId);
            if (customTrigger == null) {
                return;
            }

            BlockEventArgs newArgs = new BlockEventArgs();
            newArgs.blockPos = triggerPos;
            newArgs.zone = zone;
            newArgs.srcBlockState = targetBlockState;
            newArgs.setSrcIdentity(args.getSrcIdentity());

            for (BlockEventTrigger t : customTrigger) {
                t.act(newArgs);
            }
        }
    }

    public static void load_base_ui_components() {
        //Table table, CustomScreen screen
        components.put("row",(table,screen,data)->{
            table.row();
        });
        components.put("space",(table,screen,data)->{
            table.add()
                    .height(data.getFloat("width",10F))
                    .height(data.getFloat("height",10F));
        });
        components.put("label",(table,screen,data)->{
            LabelWidget lbl = new LabelWidget(
                    data.getString("text",""),
                    data.getFloat("x_off",0F),
                    data.getFloat("y_off",-2F)
            );
            table.add(lbl);
        });
        components.put("text_button",(table,screen,data)->{
            //Button button = new TextButton(data.getString("text",""),skin);
            TextButtonWidget button = new TextButtonWidget(data.getString("text",""));
            JsonValue events = data.get("events");
            for (JsonValue event : events) {
                String type = event.getString("type", "");
                if (type.isEmpty())
                    continue;
                if (!button_events.containsKey(type.toLowerCase()))
                    continue;
                TriConsumer<TextButtonWidget, CustomScreen, JsonValue> component = button_events.get(type.toLowerCase());
                component.accept(button, screen, event);
            }
            table.add(button);
        });
        components.put("item_slot",(table,screen,data)->{
            add_ui_slot(table,screen,data.getInt("slot",0),data.getBoolean("output",false));
        });
        components.put("table",(table,screen,data)->{
            JsonValue ui_layout = data.get("layout");
            Table new_table = new Table();
            build_ui(ui_layout,new_table,screen);

            float default_width = Math.max(new_table.getColumns(),1) * 32;
            new_table.setWidth(ui_layout.getFloat("width",default_width));
            float default_height = Math.max(new_table.getRows(),1) * 32;
            new_table.setHeight(ui_layout.getFloat("height",default_height));

            table.add(new_table);
        });
    }

    static {
        load_base_button_events();
        load_base_ui_components();
    }
}