import { world, system } from "@minecraft/server"
const radToDeg = (value) => value * (180 / Math.PI)
const degToRad = (value) => value * (Math.PI / 180)

class VectorUtilitiesClass {

    /**
     * 
     * @param {{x: Number, z: Number}} v2 
     * @returns {Number} Valor em Graus
     */
    minecraftV2ToDeg(v2) {
        let rotCalc = radToDeg(Math.atan2(v2.z, v2.x)) - 90
        if (Math.abs(rotCalc) > 180) rotCalc -= 360 * Math.sign(rotCalc)

        return rotCalc
    }
    /**
     * 
     * @param {Number} deg Valor em Graus
     * @returns {{x: Number, z: Number}}
     */
    minecraftDegtoV2(deg) {
        const degtov2 = {
            x: -Math.sin(degToRad(deg)),
            z: Math.cos(degToRad(deg)),
        }

        return degtov2
    }
    /**
     * 
     * @param {Number} deg Valor em Graus
     * @returns {{x: Number, z: Number}}
     */
    degToV2(deg) {
        const degtov2 = {
            x: Math.sin(degToRad(deg)),
            z: Math.cos(degToRad(deg)),
        }

        return degtov2

    }

    /**
     * @param {import("@minecraft/server").Vector3} v 
     * @return {Number}
     */
    someSelf(v) {
        let newVector = 0
        for (const vector in v) {
            newVector += v[vector]
        }
        return newVector
    }
    multSelf(v) {
        let newVector = 1
        for (const vector in v) {
            newVector *= v[vector]
        }


        return newVector

    }

    /**
     * @param {import("@minecraft/server").Vector3} vector3A 
     * @param {import("@minecraft/server").Vector3} vector3B
     */
    add(vector3A, vector3B) {
        const newVector = { ...vector3A }
        for (const vector in vector3B) {
            newVector[vector] = vector3A[vector] + vector3B[vector]
        }
        return newVector
    }
    /**
     * @param {import("@minecraft/server").Vector3} vector3A 
     * @param {import("@minecraft/server").Vector3} vector3B
     */
    remove(vector3A, vector3B) {
        const newVector = { ...vector3A }
        for (const vector in vector3B) {
            newVector[vector] = vector3A[vector] - vector3B[vector]
        }
        return newVector
    }
    /**
     * @param {import("@minecraft/server").Vector3} vector3A 
     * @param {import("@minecraft/server").Vector3} vector3B
     */
    mult(vector3A, vector3B) {
        const newVector = { ...vector3A }
        for (const vector in vector3B) {
            newVector[vector] = vector3A[vector] * vector3B[vector]
        }
        return newVector
    }
    /**
     * @param {import("@minecraft/server").Vector3} vector3A 
     * @param {import("@minecraft/server").Vector3} vector3B
     */
    div(vector3A, vector3B) {
        const newVector = { ...vector3A }
        for (const vector in vector3B) {
            newVector[vector] = vector3A[vector] / vector3B[vector]
        }
        return newVector
    }
    /**
     * @param {import("@minecraft/server").Vector3} vector3A 
     * @param {import("@minecraft/server").Vector3} vector3B
     */
    equal(vector3A, vector3B) {
        return vector3A.x == vector3B.x &&
            vector3A.y == vector3B.y &&
            vector3A.z == vector3B.z
    }
    /**
     * @param {import("@minecraft/server").Vector3} vector3A 
     * @param {{x?: Number, y?: Number, z?: Number}} vector3B
     */
    set(vector3A, vector3B) {
        const newVector = { ...vector3A }
        for (const vector in vector3B) {
            newVector[vector] = vector3B[vector]
        }
        return newVector
    }
    /**
     * @param {import("@minecraft/server").Vector3} vector3A 
     * @param {{x?: Number, y?: Number, z?: Number}} vector3B
     * @param {{x?: Number, y?: Number, z?: Number}} vector3C
     */
    clamp(vector3A, vector3B, vector3C) {
        const newVector = { ...vector3A }
        const clamp = (value, min, max) => Math.max(min, Math.min(max, value))
        for (const vector in vector3B) {
            newVector[vector] = clamp(newVector[vector], vector3B[vector], vector3C[vector])
        }
        return newVector
    }
    /**
     * 
     * @param {import("@minecraft/server").Vector3} vector 
     * @returns {Number}
     */
    sqrt(vector) {
        return Math.sqrt(vector.x ** 2 + vector.y ** 2 + vector.z ** 2)
    }
    /**
     * @param {import("@minecraft/server").Vector2} v1 
     * @param {import("@minecraft/server").Vector2} v2 
     * @returns 
     */
    dot(v1, v2) {
        return v1.x * v2.x + v1.z * v2.z
    }
    /**
     * @param {import("@minecraft/server").Vector3} v3 
     * @returns 
     */
    sign(v3) {
        const newVector = { ...v3 }
        for (const vector in v3) {
            newVector[vector] = Math.sign(v3[vector])
        }
        return newVector
    }
    /**
     * @param {import("@minecraft/server").Vector3} v3 
     * @returns 
     */
    abs(v3) {
        const newVector = { ...v3 }
        for (const vector in v3) {
            newVector[vector] = Math.abs(v3[vector])
        }
        return newVector
    }

    /**
     * @param {import("@minecraft/server").Vector3} from 
     * @param {import("@minecraft/server").Vector3} to 
     * @returns 
     */
    rotationTo(from, to) {
        const direction = this.directionTo(from, to)

        const angle_rad = Math.atan2(direction.z, direction.x)

        let angle_deg = (angle_rad * (180 / Math.PI)) - 90

        if (angle_deg > 180) angle_deg -= 360
        else if (angle_deg < -180) angle_deg += 360

        return angle_deg
    }
    /**
     * @param {import("@minecraft/server").Vector3} from 
     * @param {import("@minecraft/server").Vector3} to 
     * @returns 
     */
    directionTo(from, to) {
        // Calcular as diferenças entre as coordenadas dos pontos
        const deltaX = to.x - from.x
        const deltaY = to.y - from.y
        const deltaZ = to.z - from.z

        // Calcular o comprimento do vetor
        const length = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ)

        let direction
        // Verificar se o comprimento é zero (para evitar divisão por zero)
        if (length === 0) direction = { x: 0, y: 0, z: 0 } // Ponto de origem e destino são iguais
        else direction = {
            z: deltaZ / length,
            y: deltaY / length,
            x: deltaX / length
        }

        // Escalar o vetor para o intervalo de -1 a 1
        const maxComponent = Math.max(Math.abs(direction.x), Math.abs(direction.y), Math.abs(direction.z))
        if (maxComponent > 1) {
            direction.x /= maxComponent
            direction.y /= maxComponent
            direction.z /= maxComponent
        }

        return direction
    }
}

export const VectorUtilities = new VectorUtilitiesClass()