package electrosphere.menu.mainmenu;

import java.util.LinkedList;
import java.util.List;

import org.joml.Vector3f;

import electrosphere.engine.Globals;
import electrosphere.entity.types.camera.CameraEntityUtils;
import electrosphere.entity.types.creature.CreatureTemplate;
import electrosphere.game.data.creature.type.CreatureData;
import electrosphere.game.data.creature.type.visualattribute.AttributeVariant;
import electrosphere.game.data.creature.type.visualattribute.VisualAttribute;
import electrosphere.menu.MenuGenerators;
import electrosphere.menu.WindowUtils;
import electrosphere.net.parser.net.message.CharacterMessage;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.actor.ActorStaticMorph;
import electrosphere.renderer.actor.ActorUtils;
import electrosphere.renderer.anim.Animation;
import electrosphere.renderer.ui.elements.ActorPanel;
import electrosphere.renderer.ui.elements.Button;
import electrosphere.renderer.ui.elements.Div;
import electrosphere.renderer.ui.elements.FormElement;
import electrosphere.renderer.ui.elements.Label;
import electrosphere.renderer.ui.elements.ScrollableContainer;
import electrosphere.renderer.ui.elements.Slider;
import electrosphere.renderer.ui.elements.StringCarousel;
import electrosphere.renderer.ui.elementtypes.ClickableElement;
import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaFlexDirection;
import electrosphere.renderer.ui.elementtypes.Element;
import electrosphere.renderer.ui.elementtypes.ValueElement.ValueChangeEventCallback;
import electrosphere.renderer.ui.events.ClickEvent;
import electrosphere.renderer.ui.events.ValueChangeEvent;
import electrosphere.util.Utilities;

public class MenuGeneratorsMultiplayer {

    public static Element createMultiplayerCharacterSelectionWindow(){
        FormElement rVal = new FormElement();

        //button (create)
        Button createButton = new Button();
        Label createLabel = new Label(1.0f);
        createLabel.setText("Create Character");
        createButton.addChild(createLabel);
        rVal.addChild(createButton);
        createButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            WindowUtils.replaceMainMenuContents(MenuGenerators.createWorldCreationMenu());
            return false;
        }});

        return rVal;
    }

    static String selectedRace = "";
    public static Element createMultiplayerCharacterCreationWindow(){
        FormElement rVal = new FormElement();

        //select race
        StringCarousel raceCarousel = new StringCarousel(100, 125, 1.0f);
        raceCarousel.setOnValueChangeCallback(new ValueChangeEventCallback() {public void execute(ValueChangeEvent event){
            selectedRace = event.getAsString();
        }});
        for(String raceName : Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces()){
            raceCarousel.addOption(raceName);
        }
        rVal.addChild(raceCarousel);

        //button (create)
        Button createButton = new Button();
        Label createLabel = new Label(1.0f);
        createLabel.setText("Select Race");
        createButton.addChild(createLabel);
        rVal.addChild(createButton);
        createButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            WindowUtils.replaceMainMenuContents(MenuGeneratorsMultiplayer.createMultiplayerCharacterCreationTweakWindow(selectedRace));
            return false;
        }});

        return rVal;
    }

    public static Element createMultiplayerCharacterCreationTweakWindow(String race){
        // int screenTop = Globals.WINDOW_HEIGHT - 150;
        int verticalPosition = 125;
        int horizontalPosition = 300;

        //figure out race data
        CreatureData selectedRaceType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(race);

        //spawn camera so renderer doesn't crash (once render pipeline is modularized this shouldn't be necessary)
        Globals.playerCamera = CameraEntityUtils.spawnBasicCameraEntity(new Vector3f(0,0,0), new Vector3f(0,0.3f,1).normalize());
        Globals.viewMatrix = CameraEntityUtils.getCameraViewMatrix(Globals.playerCamera);
        // CameraEntityUtils.setCameraEye(Globals.playerCamera, new Vector3f(-1,3f,0).normalize());
        // CameraEntityUtils.setCameraCenter(Globals.playerCamera, new Vector3f(0,0,0));

        //create actor panel
        Actor characterActor = ActorUtils.createActorFromModelPath(selectedRaceType.getModelPath());
        ActorPanel actorPanel = new ActorPanel(Globals.renderingEngine.getOpenGLState(), 1200, 100, 500, 500, characterActor);
        actorPanel.setAnimation(Animation.ANIMATION_IDLE_1);
        actorPanel.setPosition(new Vector3f(0,-0.5f,-0.6f));
        // actorPanel.setRotation(new Quaternionf().rotateLocalY(0));
        actorPanel.setScale(new Vector3f(1.0f));

        //have to build static morph while looping through attributes
        ActorStaticMorph staticMorph = new ActorStaticMorph();

        //create creature template
        CreatureTemplate template = CreatureTemplate.create(race);

        List<Element> controlsToAdd = new LinkedList<Element>();
        //create edit controls here
        for(VisualAttribute attribute : selectedRaceType.getVisualAttributes()){
            if(attribute.getType().equals(VisualAttribute.TYPE_BONE)){
                //add label for slider
                Label sliderName = new Label(0.6f);
                sliderName.setText(attribute.getAttributeId());
                controlsToAdd.add(sliderName);
                //add a slider
                Slider boneSlider = new Slider(horizontalPosition, verticalPosition + 10, 500, 20, new Vector3f(0.1f,0.1f,0.1f), new Vector3f(1,1,1));
                float min = attribute.getMinValue();
                float max = attribute.getMaxValue();
                float defaultValue = min + (max - min)/2.0f;
                boneSlider.setMinimum(min);
                boneSlider.setMaximum(max);
                boneSlider.setValue(defaultValue);
                controlsToAdd.add(boneSlider);
                //actually add attributes to static morph
                if(attribute.getPrimaryBone() != null && staticMorph.getBoneTransforms(attribute.getPrimaryBone()) == null){
                    staticMorph.initBoneTransforms(attribute.getPrimaryBone());
                }
                if(attribute.getMirrorBone() != null && staticMorph.getBoneTransforms(attribute.getMirrorBone()) == null){
                    staticMorph.initBoneTransforms(attribute.getMirrorBone());
                }
                //add attribute to creature template
                template.putAttributeValue(attribute.getAttributeId(), defaultValue);
                //set callback for when we change the slider value to update the static morph
                boneSlider.setOnValueChangeCallback(new ValueChangeEventCallback() {public void execute(ValueChangeEvent event) {
                    if(characterActor.getStaticMorph() != null){
                        ActorStaticMorph staticMorph = characterActor.getStaticMorph();
                        staticMorph.updateValue(attribute.getSubtype(), attribute.getPrimaryBone(), event.getAsFloat());
                        if(attribute.getMirrorBone() != null){
                            staticMorph.updateValue(attribute.getSubtype(), attribute.getMirrorBone(), event.getAsFloat());
                        }
                        template.getAttributeValue(attribute.getAttributeId()).setValue(event.getAsFloat());
                    }
                }});
            } else if(attribute.getType().equals(VisualAttribute.TYPE_REMESH)){
                //add label for carousel
                Label sliderName = new Label(0.6f);
                sliderName.setText(attribute.getAttributeId());
                controlsToAdd.add(sliderName);
                //for adding the value to the creature template
                boolean hasAddedValue = false;
                //add a carousel
                StringCarousel variantCarousel = new StringCarousel(horizontalPosition, verticalPosition, 1.0f);
                for(AttributeVariant variant : attribute.getVariants()){
                    variantCarousel.addOption(variant.getId());
                    //if we haven't already added a value, add a value to the creature template
                    if(!hasAddedValue){
                        hasAddedValue = true;
                        //add attribute to template
                        template.putAttributeValue(attribute.getAttributeId(), variant.getId());
                    }
                }
                //callback for updating remesh
                variantCarousel.setOnValueChangeCallback(new ValueChangeEventCallback(){public void execute(ValueChangeEvent event) {
                    //TODO: implement updating visuals
                    template.getAttributeValue(attribute.getAttributeId()).setVariantId(event.getAsString());
                    AttributeVariant variant = null;
                    for(AttributeVariant variantCurrent : attribute.getVariants()){
                        if(variantCurrent.getId().equals(event.getAsString())){
                            variant = variantCurrent;
                            break;
                        }
                    }
                    if(variant != null){
                        Globals.assetManager.addModelPathToQueue(variant.getModel());
                        for(String mesh : variant.getMeshes()){
                            characterActor.getMeshMask().queueMesh(variant.getModel(), mesh);
                        }
                    }
                }});
                controlsToAdd.add(variantCarousel);
            }
            verticalPosition = verticalPosition + 100;
        }
        //finally set static morph
        characterActor.setActorStaticMorph(staticMorph);

        //add button to actually create the character
        Button createCharacterButton = new Button();
        Label createCharacterLabel = new Label(1.0f);
        createCharacterLabel.setText("Create");
        createCharacterButton.addChild(createCharacterLabel);
        controlsToAdd.add(createCharacterButton);
        createCharacterButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
            Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructRequestCreateCharacterMessage(Utilities.stringify(template)));
            return false;
        }});

        int width = 1800;
        int height = verticalPosition + 300;

        Div rVal = Div.createDiv();
        rVal.setFlexDirection(YogaFlexDirection.Row);

        ScrollableContainer scrollable = new ScrollableContainer(Globals.renderingEngine.getOpenGLState(), 0, 0, width, height);
        for(Element newControl : controlsToAdd){
            scrollable.addChild(newControl);
        }

        

        rVal.addChild(scrollable);
        rVal.addChild(actorPanel);
        // rVal.addChild(scrollable);

        // Label testLabel = new Label(100,215,1.0f);
        // testLabel.setText("Aaaaaaa");
        // rVal.addChild(testLabel);

        // //black texture background
        // ImagePanel imagePanel = new ImagePanel(0,0,width,height + 1000,Globals.blackTexture);
        // scrollable.addChild(imagePanel);

        return rVal;
    }


}
