import { compR } from "@thi.ng/transducers/compr";
import { __iter, iterator, iterator1 } from "@thi.ng/transducers/iterator";
import { isReduced, reduced } from "@thi.ng/transducers/reduced";
const B64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const B64_SAFE = B64_CHARS.substring(0, 62) + "-_";
function base64Decode(src) {
  return src ? new Uint8Array(iterator1(base64Decode(), src)) : (rfn) => {
    const r = rfn[2];
    let bc = 0, bs = 0;
    return compR(rfn, (acc, x) => {
      switch (x) {
        case "-":
          x = "+";
          break;
        case "_":
          x = "/";
          break;
        case "=":
          return reduced(acc);
        default:
      }
      const y = B64_CHARS.indexOf(x);
      bs = bc & 3 ? (bs << 6) + y : y;
      if (bc++ & 3) {
        acc = r(acc, 255 & bs >> (-2 * bc & 6));
      }
      return acc;
    });
  };
}
function base64Encode(...args) {
  const iter = __iter(base64Encode, args, iterator);
  if (iter) {
    return [...iter].join("");
  }
  return ([init, complete, reduce]) => {
    let state = 0;
    let b;
    const opts = { safe: false, buffer: 1024, ...args[0] };
    const chars = opts.safe ? B64_SAFE : B64_CHARS;
    const buf = [];
    return [
      init,
      (acc) => {
        switch (state) {
          case 1:
            buf.push(
              chars[b >> 18 & 63],
              chars[b >> 12 & 63],
              "=",
              "="
            );
            break;
          case 2:
            buf.push(
              chars[b >> 18 & 63],
              chars[b >> 12 & 63],
              chars[b >> 6 & 63],
              "="
            );
            break;
          default:
        }
        while (buf.length && !isReduced(acc)) {
          acc = reduce(acc, buf.shift());
        }
        return complete(acc);
      },
      (acc, x) => {
        switch (state) {
          case 0:
            state = 1;
            b = x << 16;
            break;
          case 1:
            state = 2;
            b += x << 8;
            break;
          default:
            state = 0;
            b += x;
            buf.push(
              chars[b >> 18 & 63],
              chars[b >> 12 & 63],
              chars[b >> 6 & 63],
              chars[b & 63]
            );
            if (buf.length >= opts.buffer) {
              for (let i = 0, n = buf.length; i < n && !isReduced(acc); i++) {
                acc = reduce(acc, buf[i]);
              }
              buf.length = 0;
            }
        }
        return acc;
      }
    ];
  };
}
export {
  base64Decode,
  base64Encode
};
