import { SoopyGui } from "../../../../guimanager"
import SoopyBoxElement from "../../../../guimanager/GuiElement/SoopyBoxElement"
import SoopyTextElement from "../../../../guimanager/GuiElement/SoopyTextElement"
import ButtonSetting from "./button"
import BoxWithText from "../../../../guimanager/GuiElement/BoxWithText"
import ButtonWithArrow from "../../../../guimanager/GuiElement/ButtonWithArrow"
import SoopyMouseClickEvent from "../../../../guimanager/EventListener/SoopyMouseClickEvent"
import NumberTextBox from "../../../../guimanager/GuiElement/NumberTextBox"
import SoopyContentChangeEvent from "../../../../guimanager/EventListener/SoopyContentChangeEvent"
import locationSettingHolder from "../locationSettingHolder"

class ImageLocationSetting extends ButtonSetting {
    constructor(name, description, settingId, module, defaultLocation, image, imageWBase, imageHBase){
        super(name, description, settingId, module, "Edit Position", this.editPosition, defaultLocation)
        
        this.x = this.getValue()[0]
        this.y = this.getValue()[1]
        this.scale = this.getValue()[2]

        this.image = image
        this.imageWBase = imageWBase
        this.imageHBase = imageHBase

        this.dragging = false
        this.dragOffset = [0, 0]
        this.resisizing = false
        this.resizePoint = 0
        this.resizeInitialPos=[0, 0, 0, 0, 0, 0]

        this.soopyGui = new SoopyGui()
        this.soopyGui._renderBackground = ()=>{} //remove background darkening

        this.elmSettings = new SoopyBoxElement().setLocation(0, 0, 0.25, 0.25)

        let scaleText = new SoopyTextElement().setText("&0Scale: ").setLocation(3, 0.025, 1, 0.15)
        scaleText.location.location.setRelative(false, true)
        scaleText.centeredX = false
        this.elmSettings.addChild(scaleText)

        this.scaleInput = new NumberTextBox().setText(this.scale.toFixed(2)).setLocation(Renderer.getStringWidth("Scale: ")+3, 0.025, -(Renderer.getStringWidth("Scale: ")+6), 0.15)
        this.scaleInput.location.location.setRelative(false, true)
        this.scaleInput.location.size.setRelative(false, true)
        this.elmSettings.addChild(this.scaleInput)
        this.scaleInput.text.addEvent(new SoopyContentChangeEvent().setHandler((newVal, oldVal, resetFun)=>{
            try{
                newVal = parseFloat(newVal)
                if(!isNaN(newVal)){
                    this.scale = newVal
                    this._updateValue()
                }
            }catch(e){}
        }))
        this.lastScaleRender = this.scale.toFixed(2)

        let xText = new SoopyTextElement().setText("&0X: ").setLocation(3, 0.225, 1, 0.15)
        xText.location.location.setRelative(false, true)
        xText.centeredX = false
        this.elmSettings.addChild(xText)
        this.xInput = new NumberTextBox().setText(this.x.toFixed(0)).setLocation(Renderer.getStringWidth("X: ")+3, 0.225, -(Renderer.getStringWidth("X: ")+6), 0.15)
        this.xInput.location.location.setRelative(false, true)
        this.xInput.location.size.setRelative(false, true)
        this.elmSettings.addChild(this.xInput)
        this.xInput.text.addEvent(new SoopyContentChangeEvent().setHandler((newVal, oldVal, resetFun)=>{
            try{
                newVal = parseFloat(newVal)
                if(!isNaN(newVal)){
                    this.x = newVal
                    this._updateValue()
                }
            }catch(e){}
        }))
        this.lastXRender = this.x.toFixed(0)

        let yText = new SoopyTextElement().setText("&0Y: ").setLocation(3, 0.425, 1, 0.15)
        yText.location.location.setRelative(false, true)
        yText.centeredX = false
        this.elmSettings.addChild(yText)
        this.yInput = new NumberTextBox().setText(this.y.toFixed(0)).setLocation(Renderer.getStringWidth("Y: ")+3, 0.425, -(Renderer.getStringWidth("Y: ")+6), 0.15)
        this.yInput.location.location.setRelative(false, true)
        this.yInput.location.size.setRelative(false, true)
        this.elmSettings.addChild(this.yInput)
        this.yInput.text.addEvent(new SoopyContentChangeEvent().setHandler((newVal, oldVal, resetFun)=>{
            try{
                newVal = parseFloat(newVal)
                if(!isNaN(newVal)){
                    this.y = newVal
                    this._updateValue()
                }
            }catch(e){}
        }))
        this.lastYRender = this.y.toFixed(0)

        this.soopyGui.element.addChild(this.elmSettings)

        let button = new ButtonWithArrow().setText("&0Reset").setLocation(0.125, 0.625, 0.75, 0.15)
        button.addEvent(new SoopyMouseClickEvent().setHandler(()=>{
            this.x = defaultLocation[0]
            this.y = defaultLocation[1]
            this.scale = defaultLocation[2]
            this.shadowType = defaultLocation[3]
        }))
        this.elmSettings.addChild(button)

        let button2 = new ButtonWithArrow().setText("&0Back").setLocation(0.125, 0.825, 0.75, 0.15)
        button2.addEvent(new SoopyMouseClickEvent().setHandler(()=>{
            this.soopyGui.close()
            this.guiObject.main.ctGui.open()
        }))
        this.elmSettings.addChild(button2)

        this.editGui = this.soopyGui.ctGui

        this.editGui.registerDraw((mouseX, mouseY, partialTicks)=>{
            this.renderGui(mouseX, mouseY)
            this.soopyGui._render(mouseX, mouseY, partialTicks)
        })
        this.editGui.registerClicked((mouseX, mouseY, button)=>{
            this.clicked(mouseX, mouseY)
            this.soopyGui._onClick(mouseX, mouseY, button)
        })
        this.editGui.registerMouseReleased((mouseX, mouseY)=>{
            this.released(mouseX, mouseY)
        })

        locationSettingHolder.addLocationSetting(this)
    }

    requires(toggleSetting){
        this.requiresO = toggleSetting

        toggleSetting.toggleObject.addEvent(new SoopyContentChangeEvent().setHandler((newVal, oldVal, resetFun)=>{
            if(newVal){
                this.guiObject.location.size.y.set(0.2, 500)
            }else{
                this.guiObject.location.size.y.set(0, 500)
            }
        }))
        let newVal = this.requiresO.getValue()
        if(!newVal){
            this.guiObject.location.size.y.set(0, 0)
        }

        return this
    }

    _updateValue(){
        this.setValue([this.x, this.y, this.scale, this.shadowType])
    }

    editPosition(){
        this.guiObject.main.ctGui.close()

        this.soopyGui.open()
    }

    clicked(mouseX, mouseY){
        let width = this.getWidth()
        let height = this.getHeight()

        let locations = [[this.x, this.y], [this.x+width*this.scale, this.y], [this.x, this.y+height*this.scale], [this.x+width*this.scale, this.y+height*this.scale]]

        locations.forEach((loc, i)=>{
            if(mouseX >= loc[0]-1*Math.max(1, this.scale) && mouseX <= loc[0]+1*Math.max(1, this.scale)
                && mouseY >= loc[1]-1*Math.max(1, this.scale) && mouseY <= loc[1]+1*Math.max(1, this.scale)){
                this.resisizing= true
                this.resizePoint = i
                this.resizeInitialPos = [mouseX, mouseY, this.x, this.y, width*this.scale, height*this.scale]
            }
        })
        if(this.resisizing) return;

        if(mouseX > this.x && mouseX < this.x+width*this.scale
            && mouseY>this.y && mouseY<this.y+height*this.scale){
            this.dragging = true;
            this.dragOffset = [this.x-mouseX, this.y-mouseY]
            return true
        }
        return false
    }
    released(mouseX, mouseY){
        this.updateLocation(mouseX, mouseY)
        this.dragging = false
        this.resisizing = false

        this._updateValue()
    }

    getWidth(){
        return this.imageWBase
    }

    getHeight(){
        return this.imageHBase
    }

    updateLocation(mouseX, mouseY, drawCollidingBox){
        let width = this.getWidth()
        let height = this.getHeight()

        if(this.dragging){
            this.x = mouseX+this.dragOffset[0]
            this.y = mouseY+this.dragOffset[1]

            let snapPoints = []
            locationSettingHolder.getData().forEach(loc=>{
                if(loc === this) return;
                snapPoints.push([loc.x, loc.y])
                snapPoints.push([loc.x+loc.getWidth()*loc.scale, loc.y])
                snapPoints.push([loc.x+loc.getWidth()*loc.scale, loc.y+height*loc.scale])
                snapPoints.push([loc.x, loc.y+height*loc.scale])
            })

            snapPoints.forEach(point=>{
                //top left
                if(Math.abs(this.x-point[0]) < 5 && Math.abs(this.y-point[1]) < 5){
                    this.x = point[0]
                    this.y = point[1]
                }

                //top right
                if(Math.abs(this.x+width*this.scale-point[0]) < 5 && Math.abs(this.y-point[1]) < 5){
                    this.x = point[0]-width*this.scale
                    this.y = point[1]
                }

                //bottom left
                if(Math.abs(this.x-point[0]) < 5 && Math.abs(this.y+height*this.scale-point[1]) < 5){
                    this.x = point[0]
                    this.y = point[1]-height*this.scale
                }

                //bottom right
                if(Math.abs(this.x+width*this.scale-point[0]) < 5 && Math.abs(this.y+height*this.scale-point[1]) < 5){
                    this.x = point[0]-width*this.scale
                    this.y = point[1]-height*this.scale
                }
            })
        }
        if(this.resisizing){
            if(this.resizePoint === 3){
                this.scale=(mouseX-this.x)/width
                this.scale = Math.max(0.25, this.scale)
            }
            if(this.resizePoint === 1){
                
                let [oMouseX, oMouseY, oX, oY, ow, oh] = this.resizeInitialPos
    
                this.scale=(mouseX-this.x)/width
                this.scale = Math.max(0.25, this.scale)
                this.y=oY+oh-height*this.scale
            }
            if(this.resizePoint===0){
                let [oMouseX, oMouseY, oX, oY, ow, oh] = this.resizeInitialPos
    
                this.scale=(oX+ow-mouseX)/width
                this.scale = Math.max(0.25, this.scale)
                this.x=oX+ow-width*this.scale
                this.y=oY+oh-height*this.scale
            }
            if(this.resizePoint === 2){
                let [oMouseX, oMouseY, oX, oY, ow, oh] = this.resizeInitialPos
    
                this.scale=(oX+ow-mouseX)/width
                this.scale = Math.max(0.25, this.scale)
                this.x=oX+ow-width*this.scale
            }
        }
    }

    renderGui(mouseX, mouseY){

        let width = this.getWidth()
        let height = this.getHeight()

        this.image.draw(this.x, this.y, width*this.scale, height*this.scale)

        this.updateLocation(mouseX, mouseY, true)

        this.renderBox(true)

        if(this.x+width*this.scale/2 > Renderer.screen.getWidth()/2){
            this.elmSettings.location.location.x.set(Math.min(Math.max(this.x/Renderer.screen.getWidth()-0.25-0.03, 0.02), 0.73))
        }else{
            this.elmSettings.location.location.x.set(Math.min(Math.max((this.x+width*this.scale)/Renderer.screen.getWidth()+0.03, 0.02), 0.73))
        }
        this.elmSettings.location.location.y.set(Math.min(Math.max((this.y+height*this.scale/2)/Renderer.screen.getHeight() - this.elmSettings.location.size.y.get()/2, 0.02), 0.73))

        
        if(this.lastScaleRender !== this.scale.toFixed(2) && !this.scaleInput.text.selected){
            this.lastScaleRender = this.scale.toFixed(2)
            this.scaleInput.setText(this.scale.toFixed(2))
        }
        if(this.lastXRender !== this.x.toFixed(0) && !this.xInput.text.selected){
            this.lastXRender = this.x.toFixed(0)
            this.xInput.setText(this.x.toFixed(0))
        }
        if(this.lastYRender !== this.y.toFixed(0) && !this.yInput.text.selected){
            this.lastYRender = this.y.toFixed(0)
            this.yInput.setText(this.y.toFixed(0))
        }
    }

    renderBox(drawHandles){
        let width = this.getWidth()
        let height = this.getHeight()

        Renderer.drawRect(Renderer.color(255, 255, 255), this.x, this.y, width*this.scale, 1)
        Renderer.drawRect(Renderer.color(255, 255, 255), this.x, this.y, 1, height*this.scale)
        Renderer.drawRect(Renderer.color(255, 255, 255), this.x, this.y+height*this.scale, width*this.scale, 1)
        Renderer.drawRect(Renderer.color(255, 255, 255), this.x+width*this.scale, this.y, 1, height*this.scale)

        if(drawHandles){
            Renderer.drawRect(Renderer.color(255, 255, 255), this.x-1*Math.max(1, this.scale)+width*this.scale, this.y-1*Math.max(1, this.scale), 2*Math.max(1, this.scale)+1, 2*Math.max(1, this.scale)+1)
            Renderer.drawRect(Renderer.color(255, 255, 255), this.x-1*Math.max(1, this.scale), this.y-1*Math.max(1, this.scale)+height*this.scale, 2*Math.max(1, this.scale)+1, 2*Math.max(1, this.scale)+1)
            Renderer.drawRect(Renderer.color(255, 255, 255), this.x-1*Math.max(1, this.scale)+width*this.scale, this.y-1*Math.max(1, this.scale)+height*this.scale, 2*Math.max(1, this.scale)+1, 2*Math.max(1, this.scale)+1)
            Renderer.drawRect(Renderer.color(255, 255, 255), this.x-1*Math.max(1, this.scale), this.y-1*Math.max(1, this.scale), 2*Math.max(1, this.scale)+1, 2*Math.max(1, this.scale)+1)
        }
    }
}

export default ImageLocationSetting