(() => {
  function stripComment(line) {
    const pos = line.indexOf("#");
    return pos === -1 ? line : line.slice(0, pos);
  }

  function trim(s) {
    return String(s || "").trim();
  }

  function parseOriginArray(value) {
    const start = value.indexOf("[");
    const end = value.indexOf("]");
    if (start === -1 || end === -1 || end <= start) return null;
    const parts = value
      .slice(start + 1, end)
      .split(",")
      .map((p) => Number(trim(p)))
      .filter((n) => !Number.isNaN(n));
    if (parts.length < 2) return null;
    return { origin_x: parts[0], origin_y: parts[1], origin_yaw: parts[2] || 0 };
  }

  function parseNumber(value) {
    const n = Number(value);
    return Number.isFinite(n) ? n : null;
  }

  function parseIntField(value) {
    const n = parseInt(value, 10);
    return Number.isFinite(n) ? n : null;
  }

  /**
   * Parse ROS map_server yaml (resolution, origin, thresholds).
   * @param {string} text
   * @param {{ requireImage?: boolean }} opts
   */
  function parse(text, opts = {}) {
    const requireImage = !!opts.requireImage;
    const out = {
      image: "",
      resolution: null,
      origin_x: 0,
      origin_y: 0,
      origin_yaw: 0,
      negate: 0,
      occupied_thresh: 0.65,
      free_thresh: 0.196,
    };

    for (const rawLine of String(text || "").split(/\r?\n/)) {
      const line = trim(stripComment(rawLine));
      if (!line) continue;
      const colon = line.indexOf(":");
      if (colon === -1) continue;
      const key = trim(line.slice(0, colon));
      const value = trim(line.slice(colon + 1));
      if (!value && key !== "image") continue;

      if (key === "image") out.image = value;
      else if (key === "resolution") out.resolution = parseNumber(value);
      else if (key === "origin") {
        const origin = parseOriginArray(value);
        if (origin) Object.assign(out, origin);
      } else if (key === "negate") {
        const n = parseIntField(value);
        if (n != null) out.negate = n;
      } else if (key === "occupied_thresh") {
        const n = parseNumber(value);
        if (n != null) out.occupied_thresh = n;
      } else if (key === "free_thresh") {
        const n = parseNumber(value);
        if (n != null) out.free_thresh = n;
      }
    }

    if (requireImage && !out.image) return { error: "yaml missing image field" };
    if (out.resolution == null || out.resolution <= 0) return { error: "yaml missing resolution field" };
    return out;
  }

  function serialize(meta) {
    const image = meta.image || "map.png";
    const resolution = meta.resolution != null ? meta.resolution : 0.05;
    const ox = meta.origin_x != null ? meta.origin_x : 0;
    const oy = meta.origin_y != null ? meta.origin_y : 0;
    const oyaw = meta.origin_yaw != null ? meta.origin_yaw : 0;
    const negate = meta.negate != null ? meta.negate : 0;
    const occ = meta.occupied_thresh != null ? meta.occupied_thresh : 0.65;
    const free = meta.free_thresh != null ? meta.free_thresh : 0.196;
    return [
      `image: ${image}`,
      `resolution: ${Number(resolution).toFixed(6)}`,
      `origin: [${Number(ox).toFixed(6)}, ${Number(oy).toFixed(6)}, ${Number(oyaw).toFixed(6)}]`,
      `negate: ${negate}`,
      `occupied_thresh: ${Number(occ).toFixed(3)}`,
      `free_thresh: ${Number(free).toFixed(3)}`,
      "",
    ].join("\n");
  }

  window.MapYaml = { parse, serialize };
})();
