import { Direction } from "@minecraft/server";
const DIRECTION_VECTORS = {
    [Direction.Up]: [0, 1, 0],
    [Direction.Down]: [0, -1, 0],
    [Direction.North]: [0, 0, -1],
    [Direction.South]: [0, 0, 1],
    [Direction.East]: [1, 0, 0],
    [Direction.West]: [-1, 0, 0],
};
export class Vector {
    static get ZERO() {
        return new Vector(0, 0, 0);
    }
    static get ONE() {
        return new Vector(1, 1, 1);
    }
    static get UP() {
        return new Vector(0, 1, 0);
    }
    static get DOWN() {
        return new Vector(0, -1, 0);
    }
    static get INF() {
        return new Vector(Infinity, Infinity, Infinity);
    }
    static get NEG_INF() {
        return new Vector(-Infinity, -Infinity, -Infinity);
    }
    static from(loc) {
        if (Array.isArray(loc))
            return new Vector(...loc);
        else if (typeof loc === "string")
            return new Vector(...DIRECTION_VECTORS[loc]);
        return new Vector(loc.x, loc.y, loc.z);
    }
    static add(a, b) {
        return Vector.from(a).add(b);
    }
    static sub(a, b) {
        return Vector.from(a).sub(b);
    }
    static mul(a, b) {
        return Vector.from(a).mul(b);
    }
    static div(a, b) {
        return Vector.from(a).div(b);
    }
    static min(a, b) {
        return Vector.from(a).min(b);
    }
    static max(a, b) {
        return Vector.from(a).max(b);
    }
    static equals(a, b) {
        return Vector.from(a).equals(b);
    }
    constructor(x, y, z) {
        this.vals = [0, 0, 0];
        this.vals = [x, y, z];
    }
    get x() {
        return this.vals[0];
    }
    set x(val) {
        this.vals[0] = val;
    }
    get y() {
        return this.vals[1];
    }
    set y(val) {
        this.vals[1] = val;
    }
    get z() {
        return this.vals[2];
    }
    set z(val) {
        this.vals[2] = val;
    }
    get lengthSqr() {
        return this.x * this.x + this.y * this.y + this.z * this.z;
    }
    get length() {
        return Math.hypot(...this.vals);
    }
    set length(val) {
        const len = this.length;
        this.x = (this.x / len) * val;
        this.y = (this.y / len) * val;
        this.z = (this.z / len) * val;
    }
    getIdx(idx) {
        return this.vals[idx];
    }
    setIdx(idx, val) {
        this.vals[idx] = val;
    }
    clone() {
        return new Vector(...this.vals);
    }
    equals(v) {
        v = Vector.from(v);
        return this.x == v.x && this.y == v.y && this.z == v.z;
    }
    offset(x, y, z) {
        return new Vector(this.x + x, this.y + y, this.z + z);
    }
    distanceTo(v) {
        return this.sub(v).length;
    }
    add(v) {
        if (typeof v == "number") {
            return new Vector(this.x + v, this.y + v, this.z + v);
        }
        else {
            v = Vector.from(v);
            return new Vector(this.x + v.x, this.y + v.y, this.z + v.z);
        }
    }
    sub(v) {
        if (typeof v == "number") {
            return new Vector(this.x - v, this.y - v, this.z - v);
        }
        else {
            v = Vector.from(v);
            return new Vector(this.x - v.x, this.y - v.y, this.z - v.z);
        }
    }
    mul(v) {
        if (typeof v == "number") {
            return new Vector(this.x * v, this.y * v, this.z * v);
        }
        else {
            v = Vector.from(v);
            return new Vector(this.x * v.x, this.y * v.y, this.z * v.z);
        }
    }
    div(v) {
        if (typeof v == "number") {
            return new Vector(this.x / v, this.y / v, this.z / v);
        }
        else {
            v = Vector.from(v);
            return new Vector(this.x / v.x, this.y / v.y, this.z / v.z);
        }
    }
    rotate(degrees, axis) {
        if (!degrees)
            return this.clone();
        const radians = degrees * (Math.PI / 180);
        const cos = Math.cos(radians);
        const sin = Math.sin(radians);
        if (axis === "x")
            return new Vector(this.x, Math.round(10000 * (this.y * cos - this.z * sin)) / 10000, Math.round(10000 * (this.y * sin + this.z * cos)) / 10000);
        else if (axis === "y")
            return new Vector(Math.round(10000 * (this.x * cos - this.z * sin)) / 10000, this.y, Math.round(10000 * (this.x * sin + this.z * cos)) / 10000);
        else
            return new Vector(Math.round(10000 * (this.x * cos - this.y * sin)) / 10000, Math.round(10000 * (this.x * sin + this.y * cos)) / 10000, this.z);
    }
    min(v) {
        v = Vector.from(v);
        return new Vector(Math.min(this.x, v.x), Math.min(this.y, v.y), Math.min(this.z, v.z));
    }
    max(v) {
        v = Vector.from(v);
        return new Vector(Math.max(this.x, v.x), Math.max(this.y, v.y), Math.max(this.z, v.z));
    }
    floor() {
        return new Vector(Math.floor(this.x), Math.floor(this.y), Math.floor(this.z));
    }
    ceil() {
        return new Vector(Math.ceil(this.x), Math.ceil(this.y), Math.ceil(this.z));
    }
    round() {
        return new Vector(Math.round(this.x), Math.round(this.y), Math.round(this.z));
    }
    lerp(v, t) {
        v = Vector.from(v);
        return new Vector((1 - t) * this.x + t * v.x, (1 - t) * this.y + t * v.y, (1 - t) * this.z + t * v.z);
    }
    abs() {
        return new Vector(Math.abs(this.x), Math.abs(this.y), Math.abs(this.z));
    }
    normalized() {
        const vec = new Vector(...this.vals);
        vec.length = 1;
        return vec;
    }
    dot(v) {
        v = Vector.from(v);
        return this.x * v.x + this.y * v.y + this.z * v.z;
    }
    transform(mat) {
        const [x, y, z] = this.vals;
        const vals = mat.vals;
        const w = 1 / (vals[3] * x + vals[7] * y + vals[11] * z + vals[15]);
        const result = new Vector(0, 0, 0);
        result.x = (vals[0] * x + vals[4] * y + vals[8] * z + vals[12]) * w;
        result.y = (vals[1] * x + vals[5] * y + vals[9] * z + vals[13]) * w;
        result.z = (vals[2] * x + vals[6] * y + vals[10] * z + vals[14]) * w;
        return result;
    }
    transformDirection(mat) {
        const [x, y, z] = this.vals;
        const vals = mat.vals;
        const result = new Vector(0, 0, 0);
        result.x = vals[0] * x + vals[4] * y + vals[8] * z;
        result.y = vals[1] * x + vals[5] * y + vals[9] * z;
        result.z = vals[2] * x + vals[6] * y + vals[10] * z;
        result.length = this.length;
        return result;
    }
    print() {
        return `${this.x} ${this.y} ${this.z}`;
    }
    toArray() {
        return [this.x, this.y, this.z];
    }
    *[Symbol.iterator]() {
        yield this.vals[0];
        yield this.vals[1];
        yield this.vals[2];
    }
}
Vector.prototype.toString = function () {
    return `(${this.vals[0]}, ${this.vals[1]}, ${this.vals[2]})`;
};
