function fieldNameFromId(id, prefix = "ipt") {
  if (!id) return "";
  return id.startsWith(prefix)
    ? id.slice(prefix.length).toLowerCase()
    : id.toLowerCase();
}

function formToFormData(form, opts = {}) {
  const {
    prefix = "ipt",
    idField = "iptId",
    exclude = [],
    multiSeparator = ",",
  } = opts;

  const fd = new FormData();
  const frm = form.jquery ? form[0] : form;

  // Sólo controles de formulario reales
  const controls = frm.querySelectorAll("input, select, textarea");

  for (const el of controls) {
    const type = (el.type || "").toLowerCase();
    const id = el.id || "";

    // descartar botones y derivados
    if (["button", "submit", "reset", "image"].includes(type)) continue;

    // descartar explícitos
    if (exclude.includes(id)) continue;

    // no incluir el campo id (se maneja aparte)
    if (id === idField) continue;

    // si no tiene id ni name, no sirve
    if (!id && !el.name) continue;

    const campo = fieldNameFromId(id || el.name, prefix);

    if (type === "radio") {
      if (el.checked) fd.append(campo, el.value);
      continue;
    }

    if (type === "checkbox") {
      fd.append(campo, el.checked ? 1 : 0);
      continue;
    }

    if (type === "select-multiple") {
      const values = Array.from(el.selectedOptions)
        .map((o) => o.value)
        .join(multiSeparator);
      fd.append(campo, values);
      continue;
    }

    if (type === "file") {
      if (el.files.length > 0) {
        if (el.multiple) for (const f of el.files) fd.append(campo + "[]", f);
        else fd.append(campo, el.files[0]);
      } else {
        fd.append(campo, "");
      }
      continue;
    }

    // default: text, number, date, textarea, select-one, etc.
    fd.append(campo, el.value);
  }

  return fd;
}

function buildPayload(form, idField = "iptId") {
  const fd = formToFormData(form, { idField });
  const idVal = document.getElementById(idField)?.value || "";
  fd.append("accion", idVal === "" ? "NUEVO" : "EDITAR");
  if (idVal !== "") fd.append("id", idVal);
  return fd;
}
