
import { createScalar } from "../utilities";

function castInt ( value: number | string ) {
  switch (typeof value) {
    case "string":
      if ((/e/iu).test(value)) {
        // eslint-disable-next-line no-param-reassign
        value = `${Number(value)}`;
      }

      return value.replace(/\.\d*$/u, "");
    case "number":
      return value | 0;
    default:
      throw new Error("invariant");
  }
}

function createAsInt ( bits: number ) {
  function asInt ( value: number | string, invalid: createScalar.Invalid ) {
    const int = castInt(value);
    const bigint = BigInt(int);
    const clamped = BigInt.asIntN(bits, bigint);

    if (bigint !== clamped) { return invalid("range"); }

    return `${int}`;
  }

  return {
    string: asInt,
    number: asInt,
    boolean ( value ) {
      return `${+value}`;
    },
  } as const as createScalar.Casts;
}

export const Int2Scalar = createScalar(
  "int2", "small-range integer", createAsInt(16)
);

export const Int4Scalar = createScalar(
  "int4", "integer", createAsInt(32)
);

export const Int8Scalar = createScalar(
  "int8", "large-range integer", createAsInt(64)
);
