/**
 * Shared Utilities
 *
 * Common utilities shared across all stream implementations.
 * This module provides cached TextEncoder/TextDecoder instances
 * and core binary operations.
 */
// =============================================================================
// Cached TextEncoder/TextDecoder instances
// =============================================================================
/**
 * Cached TextEncoder instance for UTF-8 encoding
 */
export const textEncoder = new TextEncoder();
/**
 * Cached TextDecoder instance for UTF-8 decoding
 * ignoreBOM: true - preserves BOM in output to match Node.js behavior
 */
export const textDecoder = new TextDecoder("utf-8", { ignoreBOM: true });
// Cache non-default decoders by encoding to avoid repeated allocations.
const _decoderCache = new Map();
/**
 * Get a cached TextDecoder instance.
 *
 * Note: For the default UTF-8 path we reuse the module-level `textDecoder`.
 */
export function getTextDecoder(encoding) {
    if (!encoding || encoding === "utf-8" || encoding === "utf8") {
        return textDecoder;
    }
    const key = encoding;
    let decoder = _decoderCache.get(key);
    if (!decoder) {
        decoder = new TextDecoder(key);
        _decoderCache.set(key, decoder);
    }
    return decoder;
}
// =============================================================================
// Binary Operations
// =============================================================================
/**
 * Convert string to Uint8Array using cached encoder
 */
export function stringToUint8Array(str) {
    return textEncoder.encode(str);
}
/**
 * Convert Uint8Array to string using cached decoder
 */
export function uint8ArrayToString(arr, encoding) {
    return getTextDecoder(encoding).decode(arr);
}
/**
 * Concatenate multiple Uint8Arrays efficiently
 */
export function concatUint8Arrays(arrays, totalLength) {
    const len = arrays.length;
    if (len === 0) {
        return new Uint8Array(0);
    }
    if (len === 1) {
        return arrays[0];
    }
    // Calculate total length with for loop for better performance
    if (totalLength === undefined) {
        let sum = 0;
        for (let i = 0; i < len; i++) {
            sum += arrays[i].length;
        }
        totalLength = sum;
    }
    const result = new Uint8Array(totalLength);
    let offset = 0;
    for (let i = 0; i < len; i++) {
        const arr = arrays[i];
        result.set(arr, offset);
        offset += arr.length;
    }
    return result;
}
/**
 * Compare two Uint8Arrays for equality
 */
export function uint8ArrayEquals(a, b) {
    const len = a.length;
    if (len !== b.length) {
        return false;
    }
    for (let i = 0; i < len; i++) {
        if (a[i] !== b[i]) {
            return false;
        }
    }
    return true;
}
/**
 * Find pattern in Uint8Array
 */
export function uint8ArrayIndexOf(haystack, needle, start = 0) {
    const needleLen = needle.length;
    if (needleLen === 0) {
        return start;
    }
    const haystackLen = haystack.length;
    if (needleLen > haystackLen) {
        return -1;
    }
    const firstByte = needle[0];
    const end = haystackLen - needleLen;
    outer: for (let i = start; i <= end; i++) {
        // Quick check first byte
        if (haystack[i] !== firstByte) {
            continue;
        }
        // Check rest of pattern
        for (let j = 1; j < needleLen; j++) {
            if (haystack[i + j] !== needle[j]) {
                continue outer;
            }
        }
        return i;
    }
    return -1;
}
/**
 * Slice Uint8Array (returns a copy)
 */
export function uint8ArraySlice(arr, start, end) {
    return arr.slice(start, end);
}
/**
 * Convert any buffer-like input to Uint8Array
 */
export function toUint8Array(input) {
    if (input instanceof Uint8Array) {
        return input;
    }
    if (typeof input === "string") {
        return textEncoder.encode(input);
    }
    if (input instanceof ArrayBuffer) {
        return new Uint8Array(input);
    }
    if (Array.isArray(input)) {
        return new Uint8Array(input);
    }
    throw new Error("Cannot convert to Uint8Array: unsupported input type");
}
/**
 * Convert any input to string
 */
export function bufferToString(input, encoding) {
    if (typeof input === "string") {
        return input;
    }
    const arr = toUint8Array(input);
    return getTextDecoder(encoding).decode(arr);
}
