const DEFAULT_QR_SECRET = "qms-branch-qr-v1";

function getQrSecret() {
  return process.env.QR_TOKEN_SECRET || DEFAULT_QR_SECRET;
}

function toBase64Url(bytes: Uint8Array) {
  let binary = "";
  bytes.forEach((byte) => {
    binary += String.fromCharCode(byte);
  });
  return btoa(binary)
    .replace(/\+/g, "-")
    .replace(/\//g, "_")
    .replace(/=+$/g, "");
}

function fromBase64Url(token: string) {
  const padded = token.replace(/-/g, "+").replace(/_/g, "/");
  const padLength = (4 - (padded.length % 4)) % 4;
  const base64 = padded + "=".repeat(padLength);
  const binary = atob(base64);
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < binary.length; i += 1) {
    bytes[i] = binary.charCodeAt(i);
  }
  return bytes;
}

function xorBytes(bytes: Uint8Array, secret: string) {
  const key = new TextEncoder().encode(secret);
  return bytes.map((byte, index) => byte ^ key[index % key.length]);
}

export type BranchQrPayload = {
  tenantCode: string;
  branchId: number;
};

export function encodeBranchQrToken(
  tenantCode: string,
  branchId: number,
  secret = getQrSecret()
) {
  const plain = `v1:${tenantCode.trim().toUpperCase()}:${Number(branchId)}`;
  const plainBytes = new TextEncoder().encode(plain);
  return toBase64Url(xorBytes(plainBytes, secret));
}

export function decodeBranchQrToken(
  token: string,
  secret = getQrSecret()
): BranchQrPayload | null {
  try {
    const plain = new TextDecoder().decode(
      xorBytes(fromBase64Url(token), secret)
    );
    const match = /^v1:([^:]+):(\d+)$/.exec(plain);
    if (!match) return null;
    return {
      tenantCode: match[1],
      branchId: Number(match[2]),
    };
  } catch {
    return null;
  }
}
