package electrosphere.menu.ingame;

import java.util.Random;

import org.joml.Vector3d;
import org.joml.Vector3f;

import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.types.camera.CameraEntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.foliage.FoliageUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.entity.types.object.ObjectUtils;
import electrosphere.game.data.creature.type.CreatureData;
import electrosphere.game.data.foliage.type.FoliageType;
import electrosphere.game.data.item.type.Item;
import electrosphere.game.data.object.type.ObjectData;
import electrosphere.logger.LoggerInterface;
import electrosphere.menu.WindowStrings;
import electrosphere.menu.WindowUtils;
import electrosphere.renderer.light.DirectionalLight;
import electrosphere.renderer.light.LightManager;
import electrosphere.renderer.ui.elements.Button;
import electrosphere.renderer.ui.elements.Div;
import electrosphere.renderer.ui.elements.Label;
import electrosphere.renderer.ui.elements.Slider;
import electrosphere.renderer.ui.elements.VirtualScrollable;
import electrosphere.renderer.ui.elements.Window;
import electrosphere.renderer.ui.elementtypes.NavigableElement.NavigationEventCallback;
import electrosphere.renderer.ui.elementtypes.ValueElement;
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.events.NavigationEvent;
import electrosphere.renderer.ui.events.ValueChangeEvent;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.EntityLookupUtils;

/**
 * Menu generators for level editor
 */
public class MenuGeneratorsLevelEditor {

    //
    //side panel
    static Window mainSidePanel;
    //width of the side panel
    static final int SIDE_PANEL_WIDTH = 500;

    //is the voxel selection window open
    static boolean voxelWindowOpen = false;

    //vertical offset from cursor position to spawn things at
    static final Vector3d cursorVerticalOffset = new Vector3d(0,0.05,0);


    /**
     * Creates the level editor side panel top view
     * @return
     */
    public static Window createLevelEditorSidePanel(){
        //setup window
        mainSidePanel = new Window(Globals.renderingEngine.getOpenGLState(),0,0,SIDE_PANEL_WIDTH,Globals.WINDOW_HEIGHT,true);
        mainSidePanel.setParentAlignContent(YogaAlignment.End);
        mainSidePanel.setParentJustifyContent(YogaJustification.End);
        mainSidePanel.setParentAlignItem(YogaAlignment.End);
        mainSidePanel.setAlignContent(YogaAlignment.Start);
        mainSidePanel.setAlignItems(YogaAlignment.Start);
        mainSidePanel.setJustifyContent(YogaJustification.Start);

        //scrollable
        VirtualScrollable scrollable = new VirtualScrollable(SIDE_PANEL_WIDTH, Globals.WINDOW_HEIGHT);
        mainSidePanel.addChild(scrollable);
        mainSidePanel.setOnNavigationCallback(new NavigationEventCallback() {public boolean execute(NavigationEvent event){
            WindowUtils.closeWindow(WindowStrings.LEVEL_EDTIOR_SIDE_PANEL);
            return false;
        }});

        fillInDefaultContent(scrollable);
        

        mainSidePanel.applyYoga(0,0);

        return mainSidePanel;
    }

    /**
     * Fills in the default content for the scrollable
     * @param scrollable
     */
    private static void fillInDefaultContent(VirtualScrollable scrollable){

        scrollable.clearChildren();

        //close button
        scrollable.addChild(Button.createButton("Close", () -> {
            WindowUtils.closeWindow(WindowStrings.LEVEL_EDTIOR_SIDE_PANEL);
        }));

        //spawn creature button
        scrollable.addChild(Button.createButton("Spawn Creature", () -> {
            fillInSpawnCreatureContent(scrollable);
        }));

        //spawn foliage button
        scrollable.addChild(Button.createButton("Spawn Foliage", () -> {
            fillInSpawnFoliageContent(scrollable);
        }));

        //spawn foliage button
        scrollable.addChild(Button.createButton("Spawn Item", () -> {
            fillInSpawnItemContent(scrollable);
        }));

        //spawn object button
        scrollable.addChild(Button.createButton("Spawn Object", () -> {
            fillInSpawnObjectContent(scrollable);
        }));

        //select voxel button
        scrollable.addChild(Button.createButton("Select Voxel Type", () -> {
            if(voxelWindowOpen){
                voxelWindowOpen = false;
                WindowUtils.closeWindow(WindowStrings.VOXEL_TYPE_SELECTION);
            } else {
                voxelWindowOpen = true;
                WindowUtils.replaceWindow(WindowStrings.VOXEL_TYPE_SELECTION,MenuGeneratorsTerrainEditing.createVoxelTypeSelectionPanel());
            }
        }));

        //entity tree view
        scrollable.addChild(Button.createButton("View Entity Tree", () -> {
            fillInEntityTreeContent(scrollable);
        }));


        //entity tree view
        scrollable.addChild(Button.createButton("Atmospheric Control", () -> {
            fillInAtmosphericControlContent(scrollable);
        }));

        mainSidePanel.applyYoga(0,0);

    }

    /**
     * Fills in the content for spawning entities
     * @param scrollable
     */
    private static void fillInSpawnCreatureContent(VirtualScrollable scrollable){

        scrollable.clearChildren();

        //back button
        scrollable.addChild(Button.createButton("Back", () -> {
            fillInDefaultContent(scrollable);
        }));

        //button for spawning all creatures
        for(CreatureData data : Globals.gameConfigCurrent.getCreatureTypeLoader().getCreatures()){
            //spawn creature button
            scrollable.addChild(Button.createButton("Spawn " + data.getCreatureId(), () -> {
                LoggerInterface.loggerEngine.INFO("spawn " + data.getCreatureId() + "!");
                Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
                Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
                Realm realm = Globals.realmManager.getRealms().iterator().next();
                Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset);
                CreatureUtils.serverSpawnBasicCreature(realm, cursorPos, data.getCreatureId(), null);
            }));
        }

        mainSidePanel.applyYoga(0,0);
    }

    /**
     * Level editor content for spawning foliage
     * @param scrollable
     */
    private static void fillInSpawnFoliageContent(VirtualScrollable scrollable){
        scrollable.clearChildren();

        //back button
        scrollable.addChild(Button.createButton("Back", () -> {
            fillInDefaultContent(scrollable);
        }));

        //button for spawning all foliage types
        for(FoliageType data : Globals.gameConfigCurrent.getFoliageMap().getFoliageList()){
            //spawn foliage button
            scrollable.addChild(Button.createButton("Spawn " + data.getName(), () -> {
                LoggerInterface.loggerEngine.INFO("spawn " + data.getName() + "!");
                Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
                Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
                Realm realm = Globals.realmManager.getRealms().iterator().next();
                Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset);
                FoliageUtils.serverSpawnTreeFoliage(realm, cursorPos, data.getName(), new Random().nextLong());
            }));
        }

        mainSidePanel.applyYoga(0,0);
    }

    /**
     * Level editor menu content for spawning items
     * @param scrollable
     */
    private static void fillInSpawnItemContent(VirtualScrollable scrollable){
        scrollable.clearChildren();

        //back button
        scrollable.addChild(Button.createButton("Back", () -> {
            fillInDefaultContent(scrollable);
        }));

        //button for spawning all foliage types
        for(Item item : Globals.gameConfigCurrent.getItemMap().getItems()){
            //spawn foliage button
            scrollable.addChild(Button.createButton("Spawn " + item.getItemId(), () -> {
                LoggerInterface.loggerEngine.INFO("spawn " + item.getItemId() + "!");
                Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
                Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
                Realm realm = Globals.realmManager.getRealms().iterator().next();
                Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset);
                ItemUtils.serverSpawnBasicItem(realm, cursorPos, item.getItemId());
            }));
        }

        mainSidePanel.applyYoga(0,0);
    }


    /**
     * Level editor menu content for spawning objects
     * @param scrollable
     */
    private static void fillInSpawnObjectContent(VirtualScrollable scrollable){
        scrollable.clearChildren();

        //back button
        scrollable.addChild(Button.createButton("Back", () -> {
            fillInDefaultContent(scrollable);
        }));

        //button for spawning all foliage types
        for(ObjectData object : Globals.gameConfigCurrent.getObjectTypeLoader().getAllObjectTypes()){
            //spawn foliage button
            scrollable.addChild(Button.createButton("Spawn " + object.getObjectId(), () -> {
                LoggerInterface.loggerEngine.INFO("spawn " + object.getObjectId() + "!");
                Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera));
                Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
                Realm realm = Globals.realmManager.getRealms().iterator().next();
                Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset);
                ObjectUtils.serverSpawnBasicObject(realm, cursorPos, object.getObjectId());
            }));
        }

        mainSidePanel.applyYoga(0,0);
    }


    /**
     * Creates tree view of entities in server
     * @param scrollable
     */
    private static void fillInEntityTreeContent(VirtualScrollable scrollable){
        scrollable.clearChildren();

        //back button
        scrollable.addChild(Button.createButton("Close", () -> {
            fillInDefaultContent(scrollable);
        }));

        //elements for the entity
        for(Entity entity : EntityLookupUtils.getAllEntities()){
            if(
                CreatureUtils.isCreature(entity) ||
                ItemUtils.isItem(entity) ||
                ObjectUtils.isObject(entity) ||
                FoliageUtils.isFoliage(entity)
            ){
                Div div = Div.createDiv();
                div.setFlexDirection(YogaFlexDirection.Row);
                div.setMaxHeight(30);
                div.setMarginBottom(5);
                div.setMarginLeft(5);
                div.setMarginRight(5);
                div.setMarginTop(5);

                //delete button
                Button deleteButton = Button.createButton("X", () -> {
                    LoggerInterface.loggerEngine.INFO("Delete " + entity.getId());
                    ServerEntityUtils.destroyEntity(entity);
                });
                deleteButton.setMarginRight(5);
                deleteButton.setMarginLeft(5);
                div.addChild(deleteButton);


                Label entityName = new Label(1.0f);
                entityName.setText("(" + entity.getId() + ") " + getEntityString(entity));
                div.addChild(entityName);


                scrollable.addChild(div);
            }
        }

        mainSidePanel.applyYoga(0,0);
    }

    /**
     * Gets the string to display for this entity in the entity tree view
     * @param e the entity
     * @return the string to display
     */
    private static String getEntityString(Entity e){
        if(CreatureUtils.isCreature(e)){
            return "Object - " + CreatureUtils.getType(e);
        } else if(ItemUtils.isItem(e)){
            return "Object - " + ItemUtils.getType(e);
        } else if(FoliageUtils.isFoliage(e)){
            return "Object - " + FoliageUtils.getFoliageType(e).getName();
        } else if(ObjectUtils.isObject(e)){
            return "Object - " + ObjectUtils.getType(e);
        }
        return "Entity Unknown Type";
    }



    /**
     * Creates atmospheric controls
     * @param scrollable
     */
    private static void fillInAtmosphericControlContent(VirtualScrollable scrollable){
        scrollable.clearChildren();

        //back button
        scrollable.addChild(Button.createButton("Close", () -> {
            fillInDefaultContent(scrollable);
        }));

        //global light direction
        scrollable.addChild(Label.createLabel("Global Light Direction"));
        Div xDiv = Div.createDiv();
        xDiv.setMaxHeight(50);
        xDiv.setFlexDirection(YogaFlexDirection.Row);
        xDiv.addChild(Label.createLabel("X: "));
        xDiv.addChild(Slider.createSlider(new ValueElement.ValueChangeEventCallback() {public void execute(ValueChangeEvent event) {
            LightManager lightManager = Globals.renderingEngine.getLightManager();
            DirectionalLight directionalLight = lightManager.getDirectionalLight();
            Vector3f direction = directionalLight.getDirection();
            direction.x = event.getAsFloat() * 2 - 1;
            directionalLight.setDirection(direction);
        }}));
        scrollable.addChild(xDiv);

        Div yDiv = Div.createDiv();
        yDiv.setMaxHeight(50);
        yDiv.setFlexDirection(YogaFlexDirection.Row);
        yDiv.addChild(Label.createLabel("Y: "));
        yDiv.addChild(Slider.createSlider(new ValueElement.ValueChangeEventCallback() {public void execute(ValueChangeEvent event) {
            LightManager lightManager = Globals.renderingEngine.getLightManager();
            DirectionalLight directionalLight = lightManager.getDirectionalLight();
            Vector3f direction = directionalLight.getDirection();
            direction.y = event.getAsFloat() * 2 - 1;
            directionalLight.setDirection(direction);
        }}));
        scrollable.addChild(yDiv);

        Div zDiv = Div.createDiv();
        zDiv.setMaxHeight(50);
        zDiv.setFlexDirection(YogaFlexDirection.Row);
        zDiv.addChild(Label.createLabel("Z: "));
        zDiv.addChild(Slider.createSlider(new ValueElement.ValueChangeEventCallback() {public void execute(ValueChangeEvent event) {
            LightManager lightManager = Globals.renderingEngine.getLightManager();
            DirectionalLight directionalLight = lightManager.getDirectionalLight();
            Vector3f direction = directionalLight.getDirection();
            direction.z = event.getAsFloat() * 2 - 1;
            directionalLight.setDirection(direction);
        }}));
        scrollable.addChild(zDiv);
        

        mainSidePanel.applyYoga(0,0);

    }


}
