import type { CryptoProvider } from '@shade/core';
import { ValidationError } from '@shade/core';

export const STREAM_ID_BYTES = 16;
export const STREAM_SECRET_BYTES = 32;

/** Generate a fresh 16-byte random streamId. */
export function generateStreamId(crypto: CryptoProvider): Uint8Array {
  return crypto.randomBytes(STREAM_ID_BYTES);
}

/** Generate a fresh 32-byte random streamSecret. */
export function generateStreamSecret(crypto: CryptoProvider): Uint8Array {
  return crypto.randomBytes(STREAM_SECRET_BYTES);
}

/** Encode a streamId as URL-safe base64 (no padding). */
export function streamIdToString(streamId: Uint8Array): string {
  if (streamId.length !== STREAM_ID_BYTES) {
    throw new ValidationError(`streamId must be ${STREAM_ID_BYTES} bytes`, 'streamId');
  }
  return base64UrlEncode(streamId);
}

/** Decode a URL-safe base64 streamId back to bytes. */
export function streamIdFromString(s: string): Uint8Array {
  const bytes = base64UrlDecode(s);
  if (bytes.length !== STREAM_ID_BYTES) {
    throw new ValidationError(`streamId must decode to ${STREAM_ID_BYTES} bytes`, 'streamId');
  }
  return bytes;
}

function base64UrlEncode(bytes: Uint8Array): string {
  let bin = '';
  for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]!);
  return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

function base64UrlDecode(s: string): Uint8Array {
  const padded = s.replace(/-/g, '+').replace(/_/g, '/');
  const pad = padded.length % 4 === 0 ? '' : '='.repeat(4 - (padded.length % 4));
  const bin = atob(padded + pad);
  const out = new Uint8Array(bin.length);
  for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
  return out;
}
