import * as mc from "@minecraft/server";
import * as GMath from "../utils/GMath";
import * as EntityU from "../utils/EntityRuntime";
import { EntityUtils } from "../utils/EntityUtils";
import blocksConfig from "../configs/blocksConfig";
//Functions
function nameBar(percent, barAmount) {
    let barText = ""
    for (let i = 1; i <= barAmount; i++) {
        if (percent >= (i / barAmount)) {
            barText = barText + "§a|"
        } else {
            barText = barText + "§7|"
        }

    }
    return barText
}
//Contianers
class StoveContainer extends EntityU.EntityObject {
    onCreate() {
        const data = this.data
        data["with_item"] = data["with_item"] != undefined ? data["with_item"] : false
        data["duration"] = data["duration"] != undefined ? data["duration"] : 0
        data["max_duration"] = 0
        data["stage"] = data["stage"] != undefined ? data["stage"] : 0
        data["max_stages"] = 0
    }
    onTick() {
        const data = this.data
        const entity = this.getEntity()
        const inventory = this.getInventory()
        const inBlock = entity.dimension.getBlock(entity.location)
        const slot = inventory.getSlot(0)
        const oldBlock = data["spawn_location"] ? entity.dimension.getBlock(data["spawn_location"]) : undefined
        if (inBlock && inBlock.typeId == "vtng_rt:stove") {
            data["spawn_location"] = inBlock.location
            if (slot.hasItem() && slot.typeId in blocksConfig.stove.items) {
                /**
                * @type {{
                * stages_uv: mc.Vector2[],
                * duration: number,
                * stages: number,
                * drop_items: {type: string, amount:number}[]
                * }}
                */
                const stoveItem = blocksConfig.stove.items[slot.typeId]
                data["max_duration"] = stoveItem.duration
                data["max_stages"] = stoveItem.stages
                if (data["with_item"] == true) {
                    entity.setProperty("vtng_rt:plant_type", stoveItem.plant_type || "cross")
                    entity.nameTag = nameBar(data["duration"] / data["max_duration"], 15)
                    if (data["duration"] < data["max_duration"]) {
                        if (inBlock.permutation.getState("vtng_rt:on") == false) { return; }
                        const timeByStage = Math.round((data["max_duration"] / data["max_stages"]))
                        entity.setProperty(`vtng_rt:uv_x`, stoveItem.stages_uv[data["stage"]].x)
                        entity.setProperty(`vtng_rt:uv_y`, stoveItem.stages_uv[data["stage"]].y)
                        data["duration"] += 1
                        if (data["duration"] % timeByStage === 0) {
                            data["stage"] += 1
                            entity.dimension.playSound("fall.gravel", entity.location)
                            entity.dimension.spawnParticle("minecraft:crop_growth_emitter", new GMath.Vector3(0, 0.5, 0).add(entity.location))
                        }
                    } else {
                        stoveItem.drop_items.forEach((e) => {
                            let amount = GMath.clamp(Math.round(e.amount * Math.random()), e.min_amount != undefined ? e.min_amount : 0, 64)
                            if (e.random == false) {
                                amount = e.amount
                            }
                            if (amount <= 0) { return; }
                            let item = new mc.ItemStack(e.type)
                            item.amount = amount
                            entity.dimension.spawnItem(item, entity.location)
                        })
                        entity.dimension.playSound("dig.gravel", entity.location)
                        slot.setItem(undefined)
                        data["with_item"] = false
                    }
                } else {
                    entity.dimension.playSound("fall.gravel", entity.location)
                    data["duration"] = 0
                    data["stage"] = 0
                    data["with_item"] = true

                }
            } else {
                entity.setProperty(`vtng_rt:uv_x`, 0)
                entity.setProperty(`vtng_rt:uv_y`, 0)
                data["duration"] = 0
                data["stage"] = 0
                data["with_item"] = false
                entity.nameTag = ""
            }
        } else {
            if (oldBlock && oldBlock.typeId == "vtng_rt:stove") {
                entity.teleport(oldBlock.bottomCenter())
            } else {
                if(slot && slot.hasItem()){
                    entity.dimension.spawnItem(slot.getItem(), entity.location)
                }
                entity.remove()
            }
        }
    }
}
class Camera extends EntityU.EntityObject {
    onCreate() {
        const entity = this.getEntity()
        const data = this.data
        data["name"] = data["name"] != undefined ? data["name"] : false
        data["camera_time"] = 0
        data["camera_max_time"] = 100
        data["rot_target"] = 70
        data["current_rot"] = entity.getProperty("vtng_rt:head_rot_y")
        data["step_mode"] = "to_left"
        data["last_rot"] = entity.getProperty("vtng_rt:head_rot_y")
        data["camera_active"] = false
        data["player_using"] = data["player_using"] || ""
    }
    onPlayerUse(){

    }
    onTick() {
        const data = this.data
        const entity = this.getEntity()
        const inBlock = entity.dimension.getBlock(entity.location)
        const oldBlock = data["spawn_location"] ? entity.dimension.getBlock(data["spawn_location"]) : undefined
        if (inBlock && inBlock.typeId == "vtng_rt:camera") {
            data["spawn_location"] = inBlock.location
            data["camera_active"] = inBlock.permutation.getState("vtng_rt:on")
            if (inBlock.permutation.getState("vtng_rt:on")) {
                if (data["camera_time"] < data["camera_max_time"]) {
                    data["camera_time"] += 2
                 //   entity.setProperty("vtng_rt:head_rot_y", rot)
                    const rot = Math.round(GMath.lerp(data["last_rot"], data["rot_target"], (data["camera_time"] / data["camera_max_time"])))
                    // console.warn(rot)
                    data["current_rot"] = rot
                    entity.setProperty("vtng_rt:head_rot_y",  data["current_rot"])
                } else {
                    data["camera_time"] = 0
                    data["last_rot"] = entity.getProperty("vtng_rt:head_rot_y")
                    if (data["step_mode"] == "to_left") {
                        data["step_mode"] = "to_center_right"
                        data["rot_target"] = 0
                    } else if (data["step_mode"] == "to_center_right") {
                        data["step_mode"] = "to_right"
                        data["rot_target"] = -70
                    } else if (data["step_mode"] == "to_right") {
                        data["step_mode"] = "to_center_left"
                        data["rot_target"] = 0
                    } else if (data["step_mode"] == "to_center_left") {
                        data["step_mode"] = "to_left"
                        data["rot_target"] = 70
                    }
                }
            }
            if(data["player_using"] != ""){
                this.onPlayerUse()
             }
        } else {
            if (oldBlock && oldBlock.typeId == "vtng_rt:camera") {
                entity.teleport(oldBlock.bottomCenter())
            } else {
                entity.remove()
            }

        }
    }
}
class Player extends EntityU.EntityObject {
    onCreate() {
        const data = this.data
        data["in_camera"] = data["in_camera"] != undefined ? data["in_camera"] : false
        data["camera_id"] = ""
    }
    onTick() {
        const data = this.data
        /** @type {mc.Player} */
        const player = this.getEntity()
        const block = player.getBlockFromViewDirection({ maxDistance: 7 })
        if (data["in_camera"]) {
            if (data["camera_id"] != "" ) {
                const cameraEntity = mc.world.getEntity(data["camera_id"])
                if (cameraEntity && (player.isSneaking == false && player.isOnGround)&& cameraEntity.getDynamicProperty("camera_active")) {
                    player.onScreenDisplay.setActionBar({ rawtext: [{ translate: `ui.vtng_rt.shift_to_close` }] })
                    const rot = (cameraEntity.getDynamicProperty("current_rot") + cameraEntity.getProperty("vtng_rt:rot_y"))
                    const direction = new GMath.Vector2(0, -1).rotate(rot, new GMath.Vector2(0, 0)).normalizeOne()
                    const location = new GMath.Vector3(0.5 * direction.x, 0.2, 0.5 * direction.y).add(cameraEntity.getHeadLocation())
                    player.camera.setCamera("minecraft:free", { "location": location, "rotation": { x: 10, y: rot }, easeOptions: {easeType:"Linear", easeTime:0.1} })
                    if(player.clientSystemInfo.platformType != "Mobile"){
                        player.onScreenDisplay.hideAllExcept()
                    }else{
                        player.onScreenDisplay.hideAllExcept([mc.HudElement.Hotbar])
                    }
                    cameraEntity.playAnimation("animation.vtng_rt.camera_invisible", {players: [player.name]})
                    data["in_camera"] = true
                } else if (player.isSneaking == true) {
                    data["camera_id"] = ""
                } else if (!cameraEntity || (cameraEntity && cameraEntity.getDynamicProperty("camera_active") == false)) {
                    data["camera_id"] = ""
                    player.sendMessage({ rawtext: [{ translate: `ui.vtng_rt.fail_to_open_camera`, with: [cameraEntity.getDynamicProperty("name")] }] })
                }
            } else {
                data["in_camera"] = false
                mc.system.runTimeout(()=>{
                    player.camera.clear()
                    player.onScreenDisplay.resetHudElements()
                }, 2)
            }
        }
        //Debug de Permutation de bloco
        // if (block) {
        //     entity.onScreenDisplay.setActionBar(`${block.block.typeId}\n${JSON.stringify(block.block.permutation.getAllStates(), null, "\n")}`)
        // }
    }
}
class Turret extends EntityU.EntityObject {
    onCreate() {
        const entity = this.getEntity()
        const data = this.data
        data["name"] = data["name"] != undefined ? data["name"] : false
        data["time"] = 0
        data["max_time"] = 100
        data["rot_target"] = 360
        data["current_rot"] = entity.getProperty("vtng_rt:head_rot_y")
        data["step_mode"] = "cicle"
        data["last_rot"] = entity.getProperty("vtng_rt:head_rot_y")
        data["camera_active"] = false
        data["targeting"] = false
        data["target_id"] = false
    }
    onTick() {
        const data = this.data
        const entity = this.getEntity()
        const inBlock = entity.dimension.getBlock(entity.location)
        let headRot = entity.getProperty("vtng_rt:head_rot_y")
        const oldBlock = data["spawn_location"] ? entity.dimension.getBlock(data["spawn_location"]) : undefined
        if (inBlock && inBlock.typeId == "vtng_rt:turret") {
            data["spawn_location"] = inBlock.location
            if (inBlock.permutation.getState("vtng_rt:on")) {
                /**
                 * @type {mc.Entity}
                 */
                let entityTarget = undefined
                let rayEntityTarget = undefined
                let targets = []
                let rayTargets = []
                const normalizeAngle = (angle)=>{
                    angle = ((angle % 360) + 360) % 360;
                    if (angle > 180) {
                        angle -= 360;
                    }
                    return angle;
                }
                let angle = normalizeAngle(headRot) + 180
                let direction = new GMath.Vector2(0, 1).rotate(angle)
                /**
                 * 
                 * @param {GMath.Vector3} position 
                 * @param {number} size 
                 */
                let createVolumeArea = function(position = new GMath.Vector3(entity.location), size = 1){
                    const volume = new GMath.Vector3(2 * size, 0, 2 * size)
                    position.x -= size
                    position.z -= size
                    return {
                        center: position,
                        area: volume
                    }
                }
                for(let i = 0; i <= 1; i+=0.1){
                    const targetR = entity.dimension.getEntitiesFromRay(new GMath.Vector3(0, i, 0).add(entity.location), new GMath.Vector3(direction.x, 0, direction.y), {maxDistance: 6, "families": ["mob", "monster"]})
                    targetR.forEach(e=>{
                        rayTargets.push(e.entity)
                    })
                }
                const volumeArea = createVolumeArea(new GMath.Vector3(inBlock), 4)
                
                targets = targets.concat(entity.dimension.getEntities({location: volumeArea.center, volume: volumeArea.area, families: ["mob", "monster"]}))
                entityTarget = targets[0]
                rayEntityTarget = rayTargets.find(e => e.id == entityTarget?.id)
                entity.setProperty('vtng_rt:open', true)
                entity.setProperty('vtng_rt:targeting', true)
                if (entityTarget) {
                    const targetRot = new GMath.Vector2(entity.location.x, entity.location.z).sub({ x: entityTarget.location.x, y: entityTarget.location.z }).getDegress()
                    if(entityTarget.isValid()){
                        entity.setProperty("vtng_rt:head_rot_y", targetRot + 90)
                    }
                    if (mc.system.currentTick % 10 === 0 && rayEntityTarget && (entityTarget.id == rayEntityTarget.id)) {
                        if(entityTarget.isValid() && entityTarget.getComponent("health").currentValue > 0 && entityTarget.id == rayEntityTarget?.id){
                            entity.playAnimation(`animation.vtng_rt.turret.shoot`)
                            entityTarget.applyDamage(3, { "cause": mc.EntityDamageCause.lightning })
                            entity.dimension.playSound(`block.end_portal.spawn`, entity.location, { volume: 0.5, pitch: 5 })
                            for (let i = 0; i < 1; i += 0.1) {
                                entity.dimension.spawnParticle("minecraft:redstone_wire_dust_particle", new GMath.Vector3(0, 1.3, 0).add(entity.location).linearLerp(new GMath.Vector3(0, 1, 0).add(entityTarget.location), i))
                            }
                        }
                    }
                }else{
                    let nextRot = GMath.clamp(headRot + 1, 0, 360)
                    if(nextRot >= 360){
                        nextRot = 0 
                    }
                    entity.setProperty("vtng_rt:head_rot_y", nextRot)
                }
            } else {
                entity.setProperty('vtng_rt:open', false)
            }
        } else {
            if (oldBlock && oldBlock.typeId == "vtng_rt:turret") {
                entity.teleport(oldBlock.bottomCenter())
            } else {
                entity.remove()
            }

        }
    }
}
class DoublePiston extends EntityU.EntityObject {
    onTick() {
        const data = this.data
        const entity = this.getEntity()
        const oldBlock = data["spawn_location"] ? entity.dimension.getBlock(data["spawn_location"]) : undefined
        const inBlock = entity.dimension.getBlock(entity.location)
        if (inBlock && inBlock.typeId.startsWith("vtng_rt:double_piston")) {
            data["spawn_location"] = inBlock.location
            entity.setProperty('vtng_rt:extended', inBlock.permutation.getState("vtng_rt:extended"))
            entity.setProperty('vtng_rt:expand_stage', inBlock.permutation.getState("vtng_rt:expand_stage"))
            entity.setProperty('vtng_rt:sticky', inBlock.permutation.hasTag("vtng_rt:piston_sticky"))
        } else {
            if (oldBlock && oldBlock.typeId.startsWith("vtng_rt:double_piston")) {
                entity.teleport(oldBlock.bottomCenter())
            } else {
                entity.remove()
            }

        }
    }
}
//     onCreate() {
//         const data = this.data
//         const entity = this.getEntity()
//         entity.clearVelocity()

//         data["redstone_power"] = data["redstone_power"] != undefined ? data["redstone_power"] : 0
//     }
//     onRotY(direction, oldRot) {

//         let rot = Math.round((oldRot + 360) % 360)
//         if (direction == 0) {
//             if (rot >= 0 && rot <= 180) {
//                 return 0
//             } else if (rot >= 180 && rot <= 360) {
//                 return 180
//             }
//         } else if (direction == 1) {
//             if (rot >= 90 && rot <= 270) {
//                 return 90
//             } else if (rot >= 270 && rot <= 360) {
//                 return -90
//             }
//         } else {
//             return oldRot
//         }
//     }
//     onTickOld() {
//         const data = this.data
//         const entity = this.getEntity()
//         let direction = new GMath.Vector3(entity.getVelocity()).normalize().round()
//         const inRail = entity.dimension.getBlock(entity.location)
//         let rot = entity.getRotation().y
//         let rotx = entity.getProperty(`vtng_rt:rot_x`)
//         let posy = -8
//         const rotVelocity = new GMath.Vector2(0, -1).rotate(rot).normalizeOne().round()
//         const railsData = {
//             "minecraft:rail": 0.03,
//             "minecraft:golden_rail": 0.007,
//             "minecraft:detector_rail": 0.03,
//             "minecraft:activator_rail": 0.03
//         }
//         const itemsType = {
//             "minecraft:redstone": {
//                 "type": "fuel",
//                 "add_fuel": 20 * 10
//             },
//             "minecraft:redstone_block": {
//                 "type": "fuel",
//                 "add_fuel": 20 * 90
//             },
//             "minecraft:rail": {
//                 "type": "block",
//                 "set_block": "minecraft:rail"
//             },
//             "minecraft:golden_rail": {
//                 "type": "block",
//                 "set_block": "minecraft:golden_rail"
//             }
//         }
//         const items = EntityUtils.getInventoryItems(entity).filter((e) => e.typeId in itemsType)
//         if (data["redstone_power"] > 0 && inRail && inRail.typeId == "minecraft:air" && (!inRail.below()?.isAir && !inRail.below()?.isLiquid && !(inRail.below()?.typeId in railsData))) {
//             const rails = items.filter((e) => itemsType[e.typeId].type == "block")
//             if (rails.length > 0) {
//                 const railItem = rails[0]
//                 const typeData = itemsType[railItem.typeId]
//                 EntityUtils.operateSlot(entity, railItem, "-", 1)
//                 inRail.setType(typeData.set_block)
//             }
//         }
//         if (inRail && inRail.typeId in railsData) {
//             const railDirection = inRail.permutation.getState("rail_direction")
//             const railData = inRail.permutation.getState("rail_data_bit")
//             posy = -8
//             if (railData != undefined && railData == false) {
//                 posy = -16
//                 //entity.setProperty("vtng_rt:pos_y", -16)
//             }

//             if (data["redstone_power"] > 0) {
//                 data["redstone_power"] -= 1
//                 const railData = railsData[inRail.typeId]
//                 let rotMode = false
//                 let velocity = new GMath.Vector3(railData * rotVelocity.x, 0, railData * rotVelocity.y)
//                 if (direction.x != 0 || direction.z != 0) {
//                     rotMode = true
//                     velocity = new GMath.Vector3(railData * direction.x, 0, railData * direction.z)
//                 }
//                 entity.applyImpulse(velocity)
//                 direction = new GMath.Vector3(entity.getVelocity()).normalize().round()

//                 if (rotMode) {
//                     const rotY = new GMath.Vector2(direction.x, direction.z).normalize().getDegress()
//                     rotx = (new GMath.Vector2(direction.x, direction.y).normalize().getDegress() / 45) / 45
//                     const rotY2 = Math.round((rotY + 360) % 360)
//                     if (railDirection == 0) {
//                         if (rotY2 >= 0 && rotY2 <= 180) {
//                             entity.setRotation({ x: 0, y: 0 })
//                         } else if (rotY2 >= 180 && rotY2 <= 360) {
//                             entity.setRotation({ x: 0, y: 180 })
//                         }
//                     } else if (railDirection == 1) {
//                         if (rotY2 >= 90 && rotY2 <= 270) {
//                             entity.setRotation({ x: 0, y: 90 })
//                         } else if (rotY2 >= 270 && rotY2 <= 360) {
//                             entity.setRotation({ x: 0, y: -90 })
//                         }
//                     } else {
//                         entity.setRotation({ x: 0, y: rotY - 90 })
//                     }

//                 }
//             } else {
//                 const fuels = items.filter((e) => itemsType[e.typeId].type == "fuel")
//                 if (fuels.length > 0) {
//                     const fuelItem = fuels[0]
//                     const typeData = itemsType[fuelItem.typeId]
//                     if (typeData.type == "fuel") {
//                         EntityUtils.operateSlot(entity, fuelItem, "-", 1)
//                         data["redstone_power"] += typeData.add_fuel
//                     }
//                 }
//             }
//         } else {
//             posy = 0
//             entity.applyImpulse(new GMath.Vector3(0, -0.1, 0))
//         }
//         entity.nameTag = "SLA"
//         if (rotx == 0 || rotx == 45) {
//             // entity.applyImpulse(new GMath.Vector3(0, -0.5, 0))
//         }
//         entity.setProperty("vtng_rt:rot_x", rotx)
//         entity.setProperty("vtng_rt:pos_y", posy)
//     }
//     onRail(){
//         const data = this.data
//         const entity = this.getEntity()
//         const currentBlock = entity.dimension.getBlock(entity.location)
//         const rails = [
//             "minecraft:activator_rail",
//             "minecraft:rail",
//             "minecraft:detector_rail",
//              "minecraft:activator_rail"
//         ]
//         if(currentBlock && rails.includes(currentBlock.typeId)){
//             return currentBlock
//         }
//         return undefined
//     }
//     onTick() {
//         const data = this.data
//         const entity = this.getEntity()
//         const currentRail = this.onRail()
//         let velocity = new GMath.Vector3(entity.getVelocity())
//         let rotation = entity.getRotation()
//         if (velocity.length() > 0) {
//             const rot = new GMath.Vector2(velocity.x, velocity.z).normalize().getDegress()
//             rotation.y = Math.round((rot + 360) % 360)
            
//         }
//         entity.setRotation(rotation)
//         if(currentRail){
//             const permutation = currentRail.permutation
//             const railDirection = permutation.getState("rail_direction")
//             if(railDirection < 6){
//                 const directionMove = new GMath.Vector2(0, 1).rotate(rotation.y).normalizeOne()
//                 entity.applyImpulse(new GMath.Vector3(0.4 * directionMove.x, 0, 0.4 * directionMove.y))
//             }
//         }
//     }
// }
//Fak
mc.world.afterEvents.entitySpawn.subscribe(data => {
    const entity = data.entity
    if (entity.typeId == "vtng_rt:rail_builder_minecart") {
        const rot = Math.round((entity.getRotation().y + 360) % 360)
        const rails = [
            "minecraft:rail",
            "minecraft:golden_rail",
            "minecraft:detector_rail"
        ]
        const block = entity.dimension.getBlock(entity.location)
        //  entity.nameTag = "entity.vtng_rt:rail_builder_minecart.name"
        if (block && rails.includes(block.typeId)) {
            const direction = block.permutation.getState("rail_direction")
            // console.warn("Teste", rot)
            if (direction == 0) {
                if (rot >= 0 && rot <= 180) {
                    entity.setRotation({ x: 0, y: 0 })
                } else if (rot >= 180 && rot <= 360) {
                    entity.setRotation({ x: 0, y: 180 })
                }
            } else if (direction == 1) {
                if (rot >= 90 && rot <= 270) {
                    entity.setRotation({ x: 0, y: 90 })
                } else if (rot >= 270 && rot <= 360) {
                    entity.setRotation({ x: 0, y: -90 })
                }
            }
        }


    }
})
//Registry
EntityU.EntityRuntime.register("vtng_rt:stove_container", StoveContainer)
EntityU.EntityRuntime.register("vtng_rt:camera", Camera)
EntityU.EntityRuntime.register("vtng_rt:turret", Turret)
EntityU.EntityRuntime.register("minecraft:player", Player)
EntityU.EntityRuntime.register("vtng_rt:double_piston_arm", DoublePiston)
//Events
mc.world.afterEvents.entityHitEntity.subscribe(data => {
    const entity = data.hitEntity
    if (entity.typeId == "vtng_rt:rail_builder_minecart") {
        const inv = EntityUtils.getInventoryItems(entity)
        inv.forEach(e => {
            entity.dimension.spawnItem(e.getItem(), entity.location)
        })
        entity.dimension.spawnItem(new mc.ItemStack("vtng_rt:rail_builder_minecart"), entity.location)
        entity.remove()
    }
})