/**
 * @file Base43 encoding/decoding, ported from Krux's pure_python_base_decode.
 */

export const B43CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ$*+-./:";
const B43_MAP = new Map<string, bigint>();
for (let i = 0; i < B43CHARS.length; i++) {
  B43_MAP.set(B43CHARS[i], BigInt(i));
}

/**
 * Decodes a Base43 string into bytes.
 * This is a direct port of the pure_python_base_decode function from Krux.
 * @param v The Base43 encoded string.
 * @returns The decoded bytes as a Uint8Array.
 */
export function base43Decode(str: string): Uint8Array {
  // Handle empty string - should return empty array
  if (str.length === 0) return new Uint8Array(0);

  // Count leading '0' characters in input (these represent leading zero bytes)
  const leadingZeroChars = str.match(/^0+/)?.[0].length || 0;

  let num = 0n;

  for (const char of str) {
    const index = B43CHARS.indexOf(char);
    if (index === -1) {
      // Match Krux error message format
      throw new Error(`forbidden character ${char} for base 43`);
    }
    num = num * 43n + BigInt(index);
  }

  // Convert BigInt to byte array
  const bytes = [];
  while (num > 0n) {
    bytes.unshift(Number(num % 256n));
    num /= 256n;
  }

  // Add leading zero bytes
  const leadingZeros = new Uint8Array(leadingZeroChars);
  return new Uint8Array([...leadingZeros, ...bytes]);
}

export function base43Encode(data: Uint8Array): string {
  let num = 0n;
  for (let i = 0; i < data.length; i++) {
    num = num * 256n + BigInt(data[i]);
  }
  let encoded = '';
  if (num === 0n) return '0';
  while (num > 0n) {
    const remainder = Number(num % 43n);
    encoded = B43CHARS[remainder] + encoded;
    num = num / 43n;
  }
  return encoded;
}
