const B64URL_RE = /^[A-Za-z0-9_-]+$/;

function bytesToBinary(bytes: Uint8Array): string {
  let binary = "";
  for (const byte of bytes) {
    binary += String.fromCharCode(byte);
  }
  return binary;
}

function binaryToBytes(binary: string): Uint8Array {
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < binary.length; i++) {
    bytes[i] = binary.charCodeAt(i);
  }
  return bytes;
}

export function encodeSessionIdForPath(sessionId: string): string {
  const bytes = new TextEncoder().encode(sessionId);
  const base64 = btoa(bytesToBinary(bytes));
  return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}

export function decodeSessionIdFromPath(encoded: string): string {
  if (encoded.startsWith("%")) {
    return decodeURIComponent(encoded);
  }
  if (!B64URL_RE.test(encoded)) {
    return encoded;
  }
  try {
    const padded = encoded.padEnd(Math.ceil(encoded.length / 4) * 4, "=");
    const base64 = padded.replace(/-/g, "+").replace(/_/g, "/");
    const binary = atob(base64);
    return new TextDecoder().decode(binaryToBytes(binary));
  } catch {
    return encoded;
  }
}

export function getSessionPath(sessionId: string): string {
  return `/session/${encodeSessionIdForPath(sessionId)}`;
}
