export enum Endian {
    BE = 'be',
    LE = 'le',
}

const UTF8_ENCODER = new TextEncoder();
const UTF8_DECODER = new TextDecoder();

function swapWord32Bytes(bytes: Uint8Array): Uint8Array {
    const out = new Uint8Array(bytes.length);
    let i = 0;
    for (; i + 4 <= bytes.length; i += 4) {
        out[i] = bytes[i + 3]!;
        out[i + 1] = bytes[i + 2]!;
        out[i + 2] = bytes[i + 1]!;
        out[i + 3] = bytes[i]!;
    }
    for (; i < bytes.length; i++) out[i] = bytes[i]!;
    return out;
}

/** 将小端数据转换为大端数据 */
export function littleEndianToBigEndian(bytes: Uint8Array): Uint8Array {
    return swapWord32Bytes(bytes);
}

/** 将大端数据转换为小端数据 */
export function bigEndianToLittleEndian(bytes: Uint8Array): Uint8Array {
    return swapWord32Bytes(bytes);
}

/** 将数字转为 4 字节二进制；endian 为 'be' 大端 或 'le' 小端 */
export function numberToBytes(value: number, endian: Endian = Endian.BE): Uint8Array {
    const buf = new Uint8Array(4);
    numberToBytesAt(value, buf, 0, endian);
    return buf;
}

/** 在 buffer 的 offset 处写入 4 字节无符号整数 */
export function numberToBytesAt(
    value: number,
    buffer: Uint8Array,
    offset: number,
    endian: Endian = Endian.BE
): void {
    if (endian === Endian.BE) {
        buffer[offset] = (value >>> 24) & 0xff;
        buffer[offset + 1] = (value >>> 16) & 0xff;
        buffer[offset + 2] = (value >>> 8) & 0xff;
        buffer[offset + 3] = value & 0xff;
    } else {
        buffer[offset] = value & 0xff;
        buffer[offset + 1] = (value >>> 8) & 0xff;
        buffer[offset + 2] = (value >>> 16) & 0xff;
        buffer[offset + 3] = (value >>> 24) & 0xff;
    }
}

/** 从 buffer 的 offset 处读取 4 字节无符号整数 */
export function bytesToNumber(
    buffer: Uint8Array,
    offset: number,
    endian: Endian = Endian.BE
): number {
    if (endian === 'be') {
        return (
            ((buffer[offset]! << 24) |
                (buffer[offset + 1]! << 16) |
                (buffer[offset + 2]! << 8) |
                buffer[offset + 3]!) >>>
            0
        );
    }
    return (
        (buffer[offset]! |
            (buffer[offset + 1]! << 8) |
            (buffer[offset + 2]! << 16) |
            (buffer[offset + 3]! << 24)) >>>
        0
    );
}

/** 将 UTF-8 字符串转为二进制 */
export function stringToBytes(str: string): Uint8Array {
    return UTF8_ENCODER.encode(str);
}

/** 将 UTF-8 二进制转为字符串 */
export function bytesToString(bytes: Uint8Array): string {
    return UTF8_DECODER.decode(bytes);
}
