package electrosphere.menu.ingame;

import org.joml.Vector3f;

import electrosphere.controls.ControlHandler.ControlsState;
import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.game.data.creature.type.CreatureData;
import electrosphere.game.data.creature.type.visualattribute.VisualAttribute;
import electrosphere.menu.WindowStrings;
import electrosphere.menu.WindowUtils;
import electrosphere.renderer.RenderingEngine;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.actor.ActorStaticMorph;
import electrosphere.renderer.model.Model;
import electrosphere.renderer.ui.elements.Button;
import electrosphere.renderer.ui.elements.Div;
import electrosphere.renderer.ui.elements.ImagePanel;
import electrosphere.renderer.ui.elements.Label;
import electrosphere.renderer.ui.elements.ScrollableContainer;
import electrosphere.renderer.ui.elements.Slider;
import electrosphere.renderer.ui.elements.TextInput;
import electrosphere.renderer.ui.elements.VirtualScrollable;
import electrosphere.renderer.ui.elements.Window;
import electrosphere.renderer.ui.elementtypes.ClickableElement;
import electrosphere.renderer.ui.elementtypes.NavigableElement.NavigationEventCallback;
import electrosphere.renderer.ui.elementtypes.ValueElement.ValueChangeEventCallback;
import electrosphere.renderer.ui.events.ClickEvent;
import electrosphere.renderer.ui.events.NavigationEvent;
import electrosphere.renderer.ui.events.ValueChangeEvent;
import electrosphere.server.saves.SaveUtils;

public class MenuGeneratorsInGame {
    
    /**
     * Creates the main in game menu that shows up when you (typically) hit the escape key
     * @return The window for the menu
     */
    public static Window createInGameMainMenu(){
        // int screenTop = Globals.WINDOW_HEIGHT - 150;
        int width = 500;
        int height = 500;
        Window rVal = new Window(Globals.renderingEngine.getOpenGLState(),0,0,width,height,true);
        // int screenLeft = (Globals.WINDOW_WIDTH - width)/2;
        Div div = Div.createDiv();
        rVal.addChild(div);
        div.setOnNavigationCallback(new NavigationEventCallback() {public boolean execute(NavigationEvent event){
            WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN), false);
            Globals.elementManager.unregisterWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN);
            if(Globals.cameraHandler.getTrackPlayerEntity()){
                Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME);
            } else {
                Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_FREE_CAMERA);
            }
            return false;
        }});
        
        //black texture background
        // ImagePanel imagePanel = new ImagePanel(0,0,width,height,Globals.blackTexture);
        // imagePanel.setWidth(width);
        // imagePanel.setHeight(height);
        // imagePanel.setTexture(Globals.assetManager.fetchTexture(Globals.blackTexture));
        // div.addChild(imagePanel);
        
        //label 1 (back)
        Button backButton = new Button();
        Label backLabel = new Label(1.0f);
        backLabel.setText("Back");
        backButton.addChild(backLabel);
        div.addChild(backButton);
        backButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN), false);
            Globals.elementManager.unregisterWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN);
            if(Globals.cameraHandler.getTrackPlayerEntity()){
                Globals.controlHandler.hintUpdateControlState(ControlsState.MAIN_GAME);
            } else {
                Globals.controlHandler.hintUpdateControlState(ControlsState.IN_GAME_FREE_CAMERA);
            }
            return false;
        }});
        
        
        //label 2 (quit)
        Button saveButton = new Button();
        Label saveLabel = new Label(1.0f);
        saveLabel.setText("Save");
        saveButton.addChild(saveLabel);
        div.addChild(saveButton);
        saveButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            Main.running = false;
            //save terrain
            saveWorld();
            return false;
        }});

        //label 3 (quit)
        Button quitButton = new Button();
        Label quitLabel = new Label(1.0f);
        quitLabel.setText("Quit");
        quitButton.addChild(quitLabel);
        div.addChild(quitButton);
        quitButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            Main.running = false;
            return false;
        }});

        //checking macro data is a poor man's check for whether we're arena or full gamemode
        // if(Globals.server != null && Globals.macroData == null){
            //label 4 (debug)
        Button debugButton = new Button();
        Label debugLabel = new Label(1.0f);
        debugLabel.setText("Debug");
        debugButton.addChild(debugLabel);
        div.addChild(debugButton);
        debugButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            WindowUtils.replaceWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN, createInGameDebugMainMenu());
            return false;
        }});
        // }

        div.addChild(Button.createButton("Open Level Editor Tools", () -> {
            WindowUtils.replaceWindow(WindowStrings.LEVEL_EDTIOR_SIDE_PANEL,MenuGeneratorsLevelEditor.createLevelEditorSidePanel());
        }));

        rVal.applyYoga(0,0);

        return rVal;
    }

    /**
     * Saves the world
     */
    static void saveWorld(){
        SaveUtils.overwriteSave(Globals.currentSave.getName());
    }

    public static Window createInGameDebugMainMenu(){
        // int screenTop = Globals.WINDOW_HEIGHT - 150;
        int width = 500;
        int height = 500;
        float fontSize = 1.0f;
        Window rVal = new Window(Globals.renderingEngine.getOpenGLState(),0,0,width,height,true);
        // int screenLeft = (Globals.WINDOW_WIDTH - width)/2;
        // Div div = new Div();
        // div.setPositionX(0);
        // div.setPositionY(0);
        // div.setWidth(500);
        // div.setHeight(500);
        VirtualScrollable scrollable = new VirtualScrollable(width, height);
        rVal.addChild(scrollable);
        // scrollable.addChild(div);
        rVal.setOnNavigationCallback(new NavigationEventCallback() {public boolean execute(NavigationEvent event){
            WindowUtils.replaceWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN, createInGameMainMenu());
            return false;
        }});
        
        //black texture background
        // ImagePanel imagePanel = new ImagePanel(0,0,width,height + 1000,Globals.blackTexture);
        // imagePanel.setWidth(width);
        // imagePanel.setHeight(height);
        // imagePanel.setTexture(Globals.assetManager.fetchTexture(Globals.blackTexture));
        // scrollable.addChild(imagePanel);
        
        //label 1 (back)
        Button backButton = new Button();
        Label backLabel = new Label(fontSize);
        backLabel.setText("Back");
        backButton.addChild(backLabel);
        scrollable.addChild(backButton);
        backButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            WindowUtils.replaceWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN, createInGameMainMenu());
            return false;
        }});
        

        //text entry (port)
        TextInput modelDebugInput = new TextInput(100,150,fontSize);
        scrollable.addChild(modelDebugInput);
        modelDebugInput.setText("Model path goes here");
        
        //label 3 (load model and debug)
        Button debugModelButton = new Button();
        Label debugModelLabel = new Label(fontSize);
        debugModelLabel.setText("Print Model Debug Info");
        debugModelButton.addChild(debugModelLabel);
        scrollable.addChild(debugModelButton);
        debugModelButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            // Main.running = false;
            Model targetModel = null;
            if((targetModel = Globals.assetManager.fetchModel(modelDebugInput.getText())) != null){
                targetModel.describeHighLevel();
            } else {
                Globals.assetManager.addModelPathToQueue(modelDebugInput.getText());
                Globals.assetManager.loadAssetsInQueue();
                if((targetModel = Globals.assetManager.fetchModel(modelDebugInput.getText())) != null){
                    targetModel.describeHighLevel();
                }
            }
            return false;
        }});

        //label 4 (reload all shaders)
        Button reloadShaderButton = new Button();
        Label reloadShaderLabel = new Label(fontSize);
        reloadShaderLabel.setText("Reload all shaders");
        reloadShaderButton.addChild(reloadShaderLabel);
        scrollable.addChild(reloadShaderButton);
        reloadShaderButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            // Main.running = false;
            Globals.assetManager.forceReloadAllShaders();
            return false;
        }});

        //reload all models
        Button reloadModelButton = new Button();
        Label reloadModelLabel = new Label(fontSize);
        reloadModelLabel.setText("Reload all models");
        reloadModelButton.addChild(reloadModelLabel);
        scrollable.addChild(reloadModelButton);
        reloadModelButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            // Main.running = false;
            Globals.assetManager.forceReloadAllModels();
            return false;
        }});

        //disable drawing player character
        Button toggleDrawPlayerButton = new Button();
        Label toggleDrawPlayerLabel = new Label(fontSize);
        toggleDrawPlayerLabel.setText("Toggle draw character");
        toggleDrawPlayerButton.addChild(toggleDrawPlayerLabel);
        scrollable.addChild(toggleDrawPlayerButton);
        toggleDrawPlayerButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            // Main.running = false;
            if(Globals.playerEntity != null){
                if(Globals.playerEntity.containsKey(EntityDataStrings.DATA_STRING_DRAW)){
                    boolean draw = (boolean)Globals.playerEntity.getData(EntityDataStrings.DATA_STRING_DRAW);
                    Globals.playerEntity.putData(EntityDataStrings.DATA_STRING_DRAW, !draw);
                }
                if(Globals.playerEntity.containsKey(EntityDataStrings.DRAW_CAST_SHADOW)){
                    boolean drawShadow = (boolean)Globals.playerEntity.getData(EntityDataStrings.DRAW_CAST_SHADOW);
                    Globals.playerEntity.putData(EntityDataStrings.DRAW_CAST_SHADOW, !drawShadow);
                }
            }
            return false;
        }});

        //pull up character editor
        Button characterSliderMenuButton = new Button();
        Label characterSliderMenuLabel = new Label(fontSize);
        characterSliderMenuLabel.setText("Character slider menu");
        characterSliderMenuButton.addChild(characterSliderMenuLabel);
        scrollable.addChild(characterSliderMenuButton);
        characterSliderMenuButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            WindowUtils.replaceWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN, createInGameCharacterSliderMenu());
            return false;
        }});

        //label (switch framebuffer)
        Button switchFramebufferButton = new Button();
        Label switchFramebufferLabel = new Label(fontSize);
        switchFramebufferLabel.setText("Switch Active Framebuffer");
        switchFramebufferButton.addChild(switchFramebufferLabel);
        scrollable.addChild(switchFramebufferButton);
        switchFramebufferButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            // Main.running = false;
            RenderingEngine.incrementOutputFramebuffer();
            return false;
        }});

        //label (toggle draw client collision spheres)
        Button toggleClientCollisionSpheresButton = new Button();
        Label toggleClientCollisionSpheresLabel = new Label(fontSize);
        toggleClientCollisionSpheresLabel.setText("Toggle draw client collision spheres");
        toggleClientCollisionSpheresButton.addChild(toggleClientCollisionSpheresLabel);
        scrollable.addChild(toggleClientCollisionSpheresButton);
        toggleClientCollisionSpheresButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            // Main.running = false;
            Globals.userSettings.setGraphicsDebugDrawCollisionSpheresClient(!Globals.userSettings.getGraphicsDebugDrawCollisionSpheresClient());
            return false;
        }});

        //label (toggle draw server collision spheres)
        Button toggleServerCollisionSpheresButton = new Button();
        Label toggleServerCollisionSpheresLabel = new Label(fontSize);
        toggleServerCollisionSpheresLabel.setText("Toggle draw server collision spheres");
        toggleServerCollisionSpheresButton.addChild(toggleServerCollisionSpheresLabel);
        scrollable.addChild(toggleServerCollisionSpheresButton);
        toggleServerCollisionSpheresButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            // Main.running = false;
            Globals.userSettings.setGraphicsDebugDrawCollisionSpheresServer(!Globals.userSettings.getGraphicsDebugDrawCollisionSpheresServer());
            return false;
        }});

        //label (toggle draw physics objects)
        Button togglePhysicsObjectsButton = new Button();
        Label togglePhysicsObjectsLabel = new Label(fontSize);
        togglePhysicsObjectsLabel.setText("Toggle draw physics objects");
        togglePhysicsObjectsButton.addChild(togglePhysicsObjectsLabel);
        scrollable.addChild(togglePhysicsObjectsButton);
        togglePhysicsObjectsButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            // Main.running = false;
            Globals.userSettings.setGraphicsDebugDrawPhysicsObjects(!Globals.userSettings.graphicsDebugDrawPhysicsObjects());
            return false;
        }});

        //label (toggle draw movement vectors)
        Button toggleMovementVectorsButton = new Button();
        Label toggleMovementVectorsLabel = new Label(fontSize);
        toggleMovementVectorsLabel.setText("Toggle draw movement vectors");
        toggleMovementVectorsButton.addChild(toggleMovementVectorsLabel);
        scrollable.addChild(toggleMovementVectorsButton);
        toggleMovementVectorsButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            // Main.running = false;
            Globals.userSettings.setGraphicsDebugDrawMovementVectors(!Globals.userSettings.graphicsDebugDrawMovementVectors());
            return false;
        }});

        //label (toggle draw navmesh)
        Button toggleNavmeshButton = new Button();
        Label toggleNavmeshLabel = new Label(fontSize);
        toggleNavmeshLabel.setText("Toggle draw navmesh");
        toggleNavmeshButton.addChild(toggleNavmeshLabel);
        scrollable.addChild(toggleNavmeshButton);
        toggleNavmeshButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            // Main.running = false;
            Globals.userSettings.setGraphicsDebugDrawNavmesh(!Globals.userSettings.graphicsDebugDrawNavmesh());
            return false;
        }});

        rVal.applyYoga(0,0);

        return rVal;
    }

    public static Window createInGameCharacterSliderMenu(){
        int width = 500;
        int height = 500;
        float fontSize = 0.4f;
        Window rVal = new Window(Globals.renderingEngine.getOpenGLState(),0,0,width,height,true);
        // int screenLeft = (Globals.WINDOW_WIDTH - width)/2;
        // Div div = new Div();
        // div.setPositionX(0);
        // div.setPositionY(0);
        // div.setWidth(500);
        // div.setHeight(500);
        ScrollableContainer scrollable = new ScrollableContainer(Globals.renderingEngine.getOpenGLState(), 0, 0, width, height);
        rVal.addChild(scrollable);
        // scrollable.addChild(div);
        rVal.setOnNavigationCallback(new NavigationEventCallback() {public boolean execute(NavigationEvent event){
            WindowUtils.replaceWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN, createInGameDebugMainMenu());
            return false;
        }});
        
        //black texture background
        ImagePanel imagePanel = new ImagePanel(0,0,width,height + 1000,Globals.blackTexture);
        // imagePanel.setWidth(width);
        // imagePanel.setHeight(height);
        // imagePanel.setTexture(Globals.assetManager.fetchTexture(Globals.blackTexture));
        scrollable.addChild(imagePanel);
        
        //label 1 (back)
        Button backButton = new Button();
        Label backLabel = new Label(fontSize);
        backLabel.setText("Back");
        backButton.addChild(backLabel);
        scrollable.addChild(backButton);
        backButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            WindowUtils.replaceWindow(WindowStrings.WINDOW_MENU_INGAME_MAIN, createInGameDebugMainMenu());
            return false;
        }});

        Entity playerEntity = Globals.playerEntity;
        Actor playerActor = EntityUtils.getActor(playerEntity);
        ActorStaticMorph staticMorph = playerActor.getStaticMorph();
        CreatureData playeCreatureType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(CreatureUtils.getType(playerEntity));
        int offset = 0;
        for(VisualAttribute attribute : playeCreatureType.getVisualAttributes()){
            int posY = offset * 350 + 100;
            if(attribute.getType().equals("bone")){
                Slider attributeSlider = new Slider(50,posY,400,100,new Vector3f(0.1f,0.1f,0.1f),new Vector3f(1.0f,0,0));
                attributeSlider.setOnValueChangeCallback(new ValueChangeEventCallback() {public void execute(ValueChangeEvent event) {
                    // float value = event.getAsFloat();
                    // float minVal = attribute.getMinValue();
                    // float range = attribute.getMaxValue() - minVal;
                    // float actualValue = minVal + range * value;
                    staticMorph.updateValue(attribute.getSubtype(), attribute.getPrimaryBone(), event.getAsFloat());
                    if(attribute.getMirrorBone() != null){
                        staticMorph.updateValue(attribute.getSubtype(), attribute.getMirrorBone(), event.getAsFloat());
                    }
                }});
                scrollable.addChild(attributeSlider);
            }
        }

        rVal.applyYoga(0,0);

        return rVal;
    }

}
