import { Direction } from "@minecraft/server";
import { degreesDifferenceAbs, wrapDegrees } from "./mthUtils";
import { SuppStates } from "../reg/suppStates";
export function vectorToDirection(delta) {
    const absX = Math.abs(delta.x);
    const absY = Math.abs(delta.y);
    const absZ = Math.abs(delta.z);
    // Find the largest component (primary axis)
    if (absX >= absY && absX >= absZ) {
        return delta.x > 0 ? Direction.East : Direction.West;
    }
    else if (absY >= absZ) {
        return delta.y > 0 ? Direction.Up : Direction.Down;
    }
    else {
        return delta.z > 0 ? Direction.South : Direction.North;
    }
}
export function getRandomDirection(excluding) {
    const dirs = allDirections.filter((d) => !excluding.includes(d));
    return dirs[Math.floor(Math.random() * dirs.length)];
}
export function directionToVector(dir) {
    switch (dir) {
        case Direction.Up:
            return { x: 0, y: 1, z: 0 };
        case Direction.Down:
            return { x: 0, y: -1, z: 0 };
        case Direction.North:
            return { x: 0, y: 0, z: -1 };
        case Direction.South:
            return { x: 0, y: 0, z: 1 };
        case Direction.East:
            return { x: 1, y: 0, z: 0 };
        case Direction.West:
            return { x: -1, y: 0, z: 0 };
    }
}
export function directionFromString(name) {
    switch (name) {
        case "up":
            return Direction.Up;
        case "down":
            return Direction.Down;
        case "north":
            return Direction.North;
        case "south":
            return Direction.South;
        case "east":
            return Direction.East;
        case "west":
            return Direction.West;
    }
    return undefined;
}
export function directionToString(dir) {
    switch (dir) {
        case Direction.Up:
            return "up";
        case Direction.Down:
            return "down";
        case Direction.North:
            return "north";
        case Direction.South:
            return "south";
        case Direction.East:
            return "east";
        case Direction.West:
            return "west";
    }
}
export function offsetVec(pos, dir, by = 1) {
    if (by == 0)
        return pos;
    switch (dir) {
        case Direction.North:
            return { x: pos.x, y: pos.y, z: pos.z - by };
        case Direction.South:
            return { x: pos.x, y: pos.y, z: pos.z + by };
        case Direction.East:
            return { x: pos.x + by, y: pos.y, z: pos.z };
        case Direction.West:
            return { x: pos.x - by, y: pos.y, z: pos.z };
        case Direction.Up:
            return { x: pos.x, y: pos.y + by, z: pos.z };
        case Direction.Down:
            return { x: pos.x, y: pos.y - by, z: pos.z };
    }
}
export function offsetPos(pos, dir, by = 1) {
    try {
        switch (dir) {
            case Direction.North:
                return pos.north(by);
            case Direction.South:
                return pos.south(by);
            case Direction.East:
                return pos.east(by);
            case Direction.West:
                return pos.west(by);
            case Direction.Up:
                return pos.above(by);
            case Direction.Down:
                return pos.below(by);
        }
    }
    catch (e) {
        return undefined;
    }
}
export function getADirection(block) {
    return getADirectionState(block.permutation);
}
export function isFacingSameWay(block, myBlock) {
    const dir1 = getADirection(block);
    const dir2 = getADirection(myBlock);
    return isSameAxis(dir1, dir2); // dumb because block trait cant use axis direction
}
export function getADirectionState(permutation) {
    return getCardinalDirection(permutation) ?? getAttachFace(permutation);
}
export function getAttachFace(permutation) {
    let attachFace = permutation.getState("minecraft:block_face");
    if (attachFace == undefined) {
        attachFace = permutation.getState("block_face");
    }
    if (attachFace == undefined) {
        attachFace = permutation.getState("torch_facing_direction");
        if (attachFace == "unknown" || attachFace == "top")
            return Direction.Up;
    }
    if (attachFace == undefined) {
        attachFace = permutation.getState("lever_direction");
        if (attachFace && attachFace.startsWith("up_"))
            return Direction.Up;
        else if (attachFace && attachFace.startsWith("down_"))
            return Direction.Down;
    }
    if (attachFace != undefined) {
        return directionFromString(attachFace);
    }
    const dir = permutation.getState("facing_direction");
    if (dir != undefined) {
        switch (dir) {
            case 0:
                return Direction.Down;
            case 1:
                return Direction.Up;
            case 3:
                return Direction.North;
            case 2:
                return Direction.South;
            case 5:
                return Direction.West;
            case 4:
                return Direction.East;
        }
    }
    return undefined;
}
export function getCardinalDirection(permutation) {
    let horizontalDir = permutation.getState("minecraft:cardinal_direction");
    if (horizontalDir == undefined) {
        horizontalDir = permutation.getState("minecraft:facing_direction");
    }
    if (horizontalDir != undefined) {
        return directionFromString(horizontalDir);
    }
    let horizontalDirInt = permutation.getState("direction");
    if (horizontalDirInt != undefined) {
        switch (horizontalDirInt) {
            case 0:
                return Direction.North;
            case 1:
                return Direction.East;
            case 2:
                return Direction.South;
            case 3:
                return Direction.West;
        }
    }
    const stairsDir = permutation.getState("weirdo_direction");
    if (stairsDir != undefined) {
        switch (stairsDir) {
            case 0:
                return Direction.East;
            case 1:
                return Direction.West;
            case 2:
                return Direction.South;
            case 3:
                return Direction.North;
        }
    }
    let axis = permutation.getState("pillar_axis");
    if (axis == undefined) {
        axis = permutation.getState(SuppStates.PillarAxis);
    }
    if (axis != undefined) {
        return axisToDirection(axis);
    }
    return undefined;
}
export function directionToAxis(face) {
    switch (face) {
        case Direction.Up:
        case Direction.Down:
            return "y";
        case Direction.North:
        case Direction.South:
            return "z";
        case Direction.East:
        case Direction.West:
            return "x";
    }
}
export function axisToDirection(axis) {
    switch (axis) {
        case "x":
            return Direction.East;
        case "y":
            return Direction.Up;
        case "z":
            return Direction.South;
    }
    return undefined;
}
export function setADirection(block, dir) {
    block.setPermutation(setADirectionState(block.permutation, dir));
}
export function setADirectionState(permutation, dir) {
    let newPerm = setCardinalDirection(permutation, dir);
    if (permutation == newPerm) {
        newPerm = setAttachFace(permutation, dir);
    }
    return newPerm;
}
export function setAttachFace(permutation, dir) {
    if (permutation.getState("minecraft:block_face") != undefined) {
        return permutation.withState("minecraft:block_face", directionToString(dir));
    }
    else if (permutation.getState("block_face") != undefined) {
        return permutation.withState("block_face", directionToString(dir));
    }
    else if (permutation.getState("torch_facing_direction") != undefined) {
        let str;
        switch (dir) {
            case Direction.Up:
                str = "top";
                break;
            case Direction.Down:
                return permutation;
            default:
                str = directionToString(dir);
                break;
        }
        return permutation.withState("torch_facing_direction", str);
    }
    else if (permutation.getState("lever_direction") != undefined) {
        let str;
        switch (dir) {
            case Direction.Up:
                str = "up_north_south";
                break;
            case Direction.Down:
                str = "down_north_south";
                break;
            default:
                str = directionToString(dir);
                break;
        }
        return permutation.withState("lever_direction", str);
    }
    else if (permutation.getState("facing_direction") != undefined) {
        let index;
        switch (dir) {
            case Direction.Down:
                index = 0;
                break;
            case Direction.North:
                index = 3;
                break;
            case Direction.South:
                index = 2;
                break;
            case Direction.West:
                index = 5;
                break;
            case Direction.East:
                index = 4;
                break;
            case Direction.Up:
                index = 1;
                break;
        }
        return permutation.withState("facing_direction", index);
    }
    return permutation;
}
export function setCardinalDirection(permutation, dir) {
    if (permutation.getState("minecraft:cardinal_direction") != undefined) {
        if (isAxisVertical(dir))
            return permutation;
        return permutation.withState("minecraft:cardinal_direction", directionToString(dir));
    }
    else if (permutation.getState("minecraft:facing_direction") != undefined) {
        return permutation.withState("minecraft:facing_direction", directionToString(dir));
    }
    else if (permutation.getState("direction") != undefined) {
        let horizontalIndex;
        switch (dir) {
            case Direction.North:
                horizontalIndex = 0;
                break;
            case Direction.East:
                horizontalIndex = 1;
                break;
            case Direction.South:
                horizontalIndex = 2;
                break;
            case Direction.West:
                horizontalIndex = 3;
                break;
            default:
                return permutation;
        }
        return permutation.withState("direction", horizontalIndex);
    }
    else if (permutation.getState("weirdo_direction") != undefined) {
        let stairsIndex;
        switch (dir) {
            case Direction.East:
                stairsIndex = 0;
                break;
            case Direction.West:
                stairsIndex = 1;
                break;
            case Direction.South:
                stairsIndex = 2;
                break;
            case Direction.North:
                stairsIndex = 3;
                break;
            default:
                return permutation;
        }
        return permutation.withState("weirdo_direction", stairsIndex);
    }
    else if (permutation.getState("pillar_axis") != undefined) {
        return permutation.withState("pillar_axis", directionToAxis(dir));
    }
    return permutation;
}
export function flipDir(dir) {
    switch (dir) {
        case Direction.Up:
            return Direction.Down;
        case Direction.Down:
            return Direction.Up;
        case Direction.North:
            return Direction.South;
        case Direction.South:
            return Direction.North;
        case Direction.East:
            return Direction.West;
        case Direction.West:
            return Direction.East;
    }
}
export function getClockwiseDir(dir) {
    switch (dir) {
        case Direction.Up:
            return Direction.East;
        case Direction.Down:
            return Direction.West;
        case Direction.North:
            return Direction.East;
        case Direction.South:
            return Direction.West;
        case Direction.East:
            return Direction.South;
        case Direction.West:
            return Direction.North;
    }
}
export function getCounterClockwiseDir(dir) {
    switch (dir) {
        case Direction.Up:
            return Direction.West;
        case Direction.Down:
            return Direction.East;
        case Direction.North:
            return Direction.West;
        case Direction.South:
            return Direction.East;
        case Direction.East:
            return Direction.North;
        case Direction.West:
            return Direction.South;
    }
}
export function isAxisVertical(dir) {
    return dir == Direction.Up || dir == Direction.Down;
}
export function isAxisPositive(dir) {
    return dir == Direction.Up || dir == Direction.East || dir == Direction.South;
}
export function isSameAxis(dir, dir2) {
    if (dir == Direction.Up || dir == Direction.Down) {
        return dir2 == Direction.Up || dir2 == Direction.Down;
    }
    if (dir == Direction.North || dir == Direction.South) {
        return dir2 == Direction.North || dir2 == Direction.South;
    }
    if (dir == Direction.East || dir == Direction.West) {
        return dir2 == Direction.East || dir2 == Direction.West;
    }
    return false;
}
export function dirToYaw(dir) {
    switch (dir) {
        case Direction.Up:
            return 0;
        case Direction.Down:
            return 0;
        case Direction.North:
            return 180;
        case Direction.South:
            return 0;
        case Direction.East:
            return 90;
        case Direction.West:
            return 270;
    }
}
export function getHorizontalViewDir(entity) {
    const d = entity.getViewDirection();
    const horizontal = { x: d.x, y: 0, z: d.z };
    return vectorToDirection(horizontal);
}
export function getClosestDir(f, valid) {
    let closest = null;
    f = wrapDegrees(f);
    let min = 360;
    for (const d of valid) {
        const angle = degreesDifferenceAbs(f, dirToYaw(d));
        if (angle < min) {
            min = angle;
            closest = d;
        }
    }
    return closest;
}
export const horizontalDirections = [Direction.North, Direction.South, Direction.East, Direction.West];
export const allDirections = [Direction.Up, Direction.Down, Direction.North, Direction.South, Direction.East, Direction.West];
