package electrosphere.client.ui.components;

import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType;
import electrosphere.client.ui.menu.WindowStrings;
import electrosphere.client.ui.menu.WindowUtils;
import electrosphere.engine.Globals;
import electrosphere.engine.assetmanager.AssetDataStrings;
import electrosphere.engine.signal.Signal.SignalType;
import electrosphere.entity.Entity;
import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.state.inventory.InventoryUtils;
import electrosphere.entity.state.inventory.RelationalInventoryState;
import electrosphere.entity.state.inventory.UnrelationalInventoryState;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.game.data.item.Item;
import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.ui.elements.Div;
import electrosphere.renderer.ui.elements.ImagePanel;
import electrosphere.renderer.ui.elements.Label;
import electrosphere.renderer.ui.elements.Tooltip;
import electrosphere.renderer.ui.elementtypes.ClickableElement.ClickEventCallback;
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaAlignment;
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaFlexDirection;
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaJustification;
import electrosphere.renderer.ui.elementtypes.ContainerElement;
import electrosphere.renderer.ui.elementtypes.DraggableElement.DragEventCallback;
import electrosphere.renderer.ui.elementtypes.Element;
import electrosphere.renderer.ui.elementtypes.HoverableElement.HoverEventCallback;
import electrosphere.renderer.ui.events.ClickEvent;
import electrosphere.renderer.ui.events.DragEvent;
import electrosphere.renderer.ui.events.HoverEvent;

/**
 * An inventory panel showing a natural inventory
 */
public class NaturalInventoryPanel {

    /**
     * The tooltip for the currently hovered item
     */
    static Tooltip itemTooltip;

    /**
     * Creates the natural inventory panel
     * @param entity The entity who has the inventory
     * @return The panel element
     */
    public static Element createNaturalInventoryPanel(Entity entity){
        UnrelationalInventoryState inventory = InventoryUtils.getNaturalInventory(entity);


        Div div = Div.createDiv();
        div.setJustifyContent(YogaJustification.Center);
        div.setMarginBottom(25);
        div.setMarginLeft(25);
        div.setMarginRight(25);
        div.setMarginTop(25);

        div.setOnDragRelease(new DragEventCallback() {public boolean execute(DragEvent event){
            LoggerInterface.loggerUI.INFO("Natural inventory received drag release event");
            if(Globals.draggedItem != null){
                if(Globals.dragSourceInventory != inventory){
                    if(Globals.dragSourceInventory instanceof RelationalInventoryState){
                        if(ClientEquipState.hasEquipState(entity) && InventoryUtils.hasEquipInventory(entity)){
                            RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(entity);
                            ClientEquipState equipState = ClientEquipState.getEquipState(entity);
                            equipState.commandAttemptUnequip(equipInventory.getItemSlot(Globals.draggedItem));
                        }
                    } if(Globals.dragSourceInventory instanceof UnrelationalInventoryState){
                        //transfer item
                        // sourceInventory.removeItem(Globals.draggedItem);
                        // inventory.addItem(Globals.draggedItem);
                        // //null out global state
                        // Globals.dragSourceInventory = null;
                        // Globals.draggedItem = null;
                        Entity item = Globals.draggedItem;
                        if(ClientEquipState.hasEquipState(entity) && InventoryUtils.hasEquipInventory(entity)){
                            RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(entity);
                            ClientEquipState equipState = ClientEquipState.getEquipState(entity);
                            equipState.commandAttemptUnequip(equipInventory.getItemSlot(item));
                        }
                        //clear item container ui
                        WindowUtils.cleanItemDraggingWindow();
                        //re-render inventory
                        WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, PlayerInventoryWindow.createPlayerInventoryWindow(Globals.playerEntity));
                    }
                }
            }
            //play sound effect
            if(Globals.virtualAudioSourceManager != null){
                Item itemData = Globals.gameConfigCurrent.getItemMap().getItem(ItemUtils.getType(Globals.draggedItem));
                if(itemData.getItemAudio() != null && itemData.getItemAudio().getUIReleaseAudio() != null){
                    Globals.virtualAudioSourceManager.createVirtualAudioSource(itemData.getItemAudio().getUIReleaseAudio(), VirtualAudioSourceType.UI, false);
                } else {
                    Globals.virtualAudioSourceManager.createVirtualAudioSource(AssetDataStrings.UI_SFX_ITEM_RELEASE, VirtualAudioSourceType.UI, false);
                }
            }
            //clear ui
            WindowUtils.cleanItemDraggingWindow();
            //re-render inventory
            WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, PlayerInventoryWindow.createPlayerInventoryWindow(Globals.playerEntity));
            return true;
        }});

        div.setOnClick(new ClickEventCallback() {public boolean execute(ClickEvent event){
            WindowUtils.focusWindow(WindowStrings.WINDOW_MENU_INVENTORY);
            return false;
        }});
        

        //label 1 (inventory)
        Label menuTitle = Label.createLabel("INVENTORY");
        menuTitle.setMarginBottom(10);
        div.addChild(menuTitle);

        {
            //contains all the item panels
            Div panelContainer = Div.createDiv();
            panelContainer.setFlexDirection(YogaFlexDirection.Row);

            for(int i = 0; i < inventory.getCapacity(); i++){
                String texturePath = "Textures/ui/uiFrame1.png";
                boolean hasItem = false;
                Entity currentItem = null;
                if(i < inventory.getItems().size() && inventory.getItems().get(i) != Globals.draggedItem){
                    currentItem = inventory.getItems().get(i);
                    //get texture path from item
                    texturePath = ItemUtils.getItemIcon(currentItem);
                    //flag that this isn't an empty slot
                    hasItem = true;
                }
                Entity finalEnt = currentItem;
                if(!Globals.assetManager.hasLoadedTexture(texturePath)){
                    Globals.assetManager.addTexturePathtoQueue(texturePath);
                }
                int panelWidth = 50;
                int panelHeight = 50;
                ImagePanel panel = ImagePanel.createImagePanel(texturePath);
                panel.setMinWidth(panelWidth);
                panel.setMinHeight(panelHeight);
                panel.setMarginRight(15);
                panel.setMarginBottom(15);
                panel.setMarginLeft(15);
                panel.setMarginTop(15);
                panel.setAlignSelf(YogaAlignment.Start);
                panel.setAbsolutePosition(false);
                if(hasItem == true && inventory.getItems().get(i) != Globals.draggedItem){
                    int itemId = i;
                    panel.setOnDragStart(new DragEventCallback() {public boolean execute(DragEvent event){
                        // System.out.println("Drag start");
                        Globals.dragSourceInventory = inventory;
                        Globals.draggedItem = inventory.getItems().get(itemId);
                        ContainerElement container = (ContainerElement)panel.getParent();
                        container.removeChild(panel);
                        WindowUtils.pushItemIconToItemWindow(panel);
                        //set new flex values now that its in this item dragging window
                        panel.setAbsolutePosition(true);
                        panel.setPositionX(panel.getAbsoluteX());
                        panel.setPositionY(panel.getAbsoluteY());
                        WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, PlayerInventoryWindow.createPlayerInventoryWindow(Globals.playerEntity));
                        //play sound effect
                        if(Globals.virtualAudioSourceManager != null){
                            Item itemData = Globals.gameConfigCurrent.getItemMap().getItem(ItemUtils.getType(finalEnt));
                            if(itemData.getItemAudio() != null && itemData.getItemAudio().getUIGrabAudio() != null){
                                Globals.virtualAudioSourceManager.createVirtualAudioSource(itemData.getItemAudio().getUIGrabAudio(), VirtualAudioSourceType.UI, false);
                            } else {
                                Globals.virtualAudioSourceManager.createVirtualAudioSource(AssetDataStrings.UI_SFX_ITEM_GRAB, VirtualAudioSourceType.UI, false);
                            }
                        }
                        return false;
                    }});
                    panel.setOnDrag(new DragEventCallback() {public boolean execute(DragEvent event){
                        // System.out.println("Drag");
                        panel.setPositionX(event.getCurrentX() - panelWidth / 2);
                        panel.setPositionY(event.getCurrentY() - panelHeight / 2);
                        Globals.signalSystem.post(SignalType.YOGA_APPLY, Globals.elementService.getWindow(WindowStrings.WINDOW_ITEM_DRAG_CONTAINER));
                        return false;
                    }});
                    panel.setOnDragRelease(new DragEventCallback(){public boolean execute(DragEvent event){
                        if(panel.getParent() != div){
                            if(panel.getParent() != null){
                                ContainerElement container = (ContainerElement)panel.getParent();
                                container.removeChild(panel);
                            }
                            panel.setAbsolutePosition(false);
                            Globals.elementService.fireEvent(event, event.getCurrentX(), event.getCurrentY());
                        }
                        return false;
                    }});
                    panel.setOnHoverCallback(new HoverEventCallback() {public boolean execute(HoverEvent event){
                        if(event.isHovered() && Globals.draggedItem == null){
                            if(itemTooltip != null){
                                Tooltip.destroy(itemTooltip);
                            }
                            Entity itemEntity = finalEnt;
                            Item itemData = Globals.gameConfigCurrent.getItemMap().getItem(itemEntity);
                            Globals.signalSystem.post(SignalType.UI_MODIFICATION,()->{
                                itemTooltip = Tooltip.create(null,
                                    Div.createCol(Label.createLabel(itemData.getId()))
                                );
                                itemTooltip.setPositionX(panel.getAbsoluteX() + panelWidth);
                                itemTooltip.setPositionY(panel.getAbsoluteY());
                            });
                        } else {
                            if(itemTooltip != null){
                                Tooltip.destroy(itemTooltip);
                            }
                        }
                        return false;
                    }});
                } else {
                    panel.setOnDragRelease(new DragEventCallback(){public boolean execute(DragEvent event){
                        if(Globals.dragSourceInventory instanceof RelationalInventoryState){
                            if(Globals.dragSourceInventory == InventoryUtils.getToolbarInventory(entity)){
                                InventoryUtils.clientAddToNatural(Globals.draggedItem);
                            } else if(Globals.dragSourceInventory == InventoryUtils.getEquipInventory(entity)){
                                RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(entity);
                                ClientEquipState equipState = ClientEquipState.getEquipState(entity);
                                equipState.commandAttemptUnequip(equipInventory.getItemSlot(Globals.draggedItem));
                            }
                        } else if(Globals.dragSourceInventory instanceof UnrelationalInventoryState){
                            if(ItemUtils.getContainingParent(Globals.draggedItem) != Globals.playerEntity){
                                throw new UnsupportedOperationException("Unimplemented!");
                            }
                        }
                        Item itemData = Globals.gameConfigCurrent.getItemMap().getItem(ItemUtils.getType(Globals.draggedItem));
                        if(itemData.getItemAudio() != null && itemData.getItemAudio().getUIReleaseAudio() != null){
                            Globals.virtualAudioSourceManager.createVirtualAudioSource(itemData.getItemAudio().getUIReleaseAudio(), VirtualAudioSourceType.UI, false);
                        } else {
                            Globals.virtualAudioSourceManager.createVirtualAudioSource(AssetDataStrings.UI_SFX_ITEM_RELEASE, VirtualAudioSourceType.UI, false);
                        }
                        //update ui
                        Globals.dragSourceInventory = null;
                        Globals.draggedItem = null;
                        //clear item container ui
                        WindowUtils.cleanItemDraggingWindow();
                        //rerender inventories
                        WindowUtils.replaceWindow(WindowStrings.WINDOW_CHARACTER, PlayerInventoryWindow.createPlayerInventoryWindow(Globals.playerEntity));
                        return false;
                    }});
                }
                panelContainer.addChild(panel);
            }
            div.addChild(panelContainer);
        }
        return div;
    }

}
