import { Option } from "effect";
import { evaluationError } from "./errors.js";
import { Decimal } from "./decimal.js";
function coerceScalar(value) {
  if (value instanceof Blob) return value;
  if (value instanceof Decimal) return value.toString();
  if (value instanceof Date) return value.toISOString();
  if (typeof value === "string") return value;
  if (typeof value === "boolean") return value ? "true" : "false";
  if (typeof value === "number" || typeof value === "bigint") return String(value);
  throw evaluationError(
    "invalid_form_value",
    `form(): unsupported value type ${Object.prototype.toString.call(value)}`
  );
}
function appendEntry(fd, key, value) {
  if (value === null || value === void 0) return;
  if (Option.isOption(value)) {
    if (Option.isSome(value)) appendEntry(fd, key, value.value);
    return;
  }
  if (Array.isArray(value)) {
    for (const item of value) appendEntry(fd, key, item);
    return;
  }
  if (value instanceof Blob) {
    fd.append(key, value);
    return;
  }
  if (typeof value === "object" && !(value instanceof Decimal) && !(value instanceof Date)) {
    throw evaluationError(
      "invalid_form_value",
      `form(): nested object values are not supported (key: "${key}")`
    );
  }
  fd.append(key, coerceScalar(value));
}
export function registerFormBuiltins(registry) {
  registry.registerType("FormData", FormData);
  registry.registerFunctionOverload("form(dyn): FormData", (record) => {
    if (record === null || record === void 0) {
      throw evaluationError("invalid_form_value", "form(): expected a map, got null");
    }
    const fd = new FormData();
    if (record instanceof Map) {
      for (const [k, v] of record) appendEntry(fd, String(k), v);
      return fd;
    }
    if (typeof record !== "object" || Array.isArray(record)) {
      throw evaluationError("invalid_form_value", "form(): expected a map");
    }
    for (const key of Object.keys(record)) {
      if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
      appendEntry(fd, key, record[key]);
    }
    return fd;
  });
}
