function clampDigits(raw) {
  const parsed = Number(raw);
  if (!Number.isFinite(parsed)) return 4;
  return Math.max(1, Math.min(4, Math.round(parsed)));
}

function sanitizeValue(raw, maxDigits) {
  return String(raw || "")
    .replace(/\D+/g, "")
    .slice(0, maxDigits);
}

function sanitizeName(raw) {
  return String(raw || "")
    .replace(/\s+/g, " ")
    .trimStart();
}

function isBlankRow(row) {
  return !row || (!String(row.value || "").trim() && !String(row.name || "").trim());
}

function normalizeRows(raw, maxDigits) {
  if (!Array.isArray(raw)) return [];
  return raw
    .filter((row) => row && typeof row === "object" && !Array.isArray(row))
    .map((row) => ({
      value: sanitizeValue(row.value, maxDigits),
      name: sanitizeName(row.name),
    }));
}

function ensureTrailingBlankRow(rows) {
  const next = rows.map((row) => ({
    value: String(row.value || ""),
    name: String(row.name || ""),
  }));
  if (!next.length || !isBlankRow(next[next.length - 1])) {
    next.push({ value: "", name: "" });
  }
  return next;
}

function persistedRows(rows) {
  return rows
    .filter((row) => !isBlankRow(row))
    .map((row) => ({
      value: String(row.value || ""),
      name: String(row.name || ""),
    }));
}

function totalValue(rows) {
  return persistedRows(rows).reduce((sum, row) => sum + (Number.parseInt(row.value, 10) || 0), 0);
}

function normalizeConfig(state) {
  const maxDigits = clampDigits(state.max_digits);
  return {
    leftLabel: String(state.left_label || "Value").trim() || "Value",
    rightLabel: String(state.right_label || "Item").trim() || "Item",
    totalLabel: String(state.total_label || "Total").trim() || "Total",
    totalSuffix: String(state.total_suffix || "").trim(),
    maxDigits,
    score:
      typeof state.score === "number" && Number.isFinite(state.score)
        ? Math.max(0, Math.min(100, state.score))
        : 24,
    rows: ensureTrailingBlankRow(normalizeRows(state.rows, maxDigits)),
  };
}

function configState(config) {
  return {
    left_label: config.leftLabel,
    right_label: config.rightLabel,
    total_label: config.totalLabel,
    total_suffix: config.totalSuffix,
    max_digits: config.maxDigits,
    score: config.score,
    rows: persistedRows(config.rows),
  };
}

function autoscore(config) {
  if (typeof config.score === "number" && Number.isFinite(config.score) && config.score > 0) {
    return config.score;
  }
  return persistedRows(config.rows).length ? 24 : 16;
}

export function mount({ root, state, host }) {
  const labelsEl = root.querySelector(".list-total-card-ui__labels");
  const rowsEl = root.querySelector(".list-total-card-ui__rows");
  const statusEl = root.querySelector(".list-total-card-ui__status");
  const totalLabelEl = root.querySelector(".list-total-card-ui__total-label");
  const totalEl = root.querySelector(".list-total-card-ui__total-value");

  if (
    !(labelsEl instanceof HTMLElement) ||
    !(rowsEl instanceof HTMLElement) ||
    !(statusEl instanceof HTMLElement) ||
    !(totalLabelEl instanceof HTMLElement) ||
    !(totalEl instanceof HTMLElement)
  ) {
    return;
  }

  const leftLabelEl = labelsEl.children.item(0);
  const rightLabelEl = labelsEl.children.item(1);
  if (!(leftLabelEl instanceof HTMLElement) || !(rightLabelEl instanceof HTMLElement)) return;

  let config = normalizeConfig(state);
  let saveTimer = null;
  let busy = false;

  const clearSaveTimer = () => {
    if (saveTimer !== null) {
      window.clearTimeout(saveTimer);
      saveTimer = null;
    }
  };

  const setStatus = (text, kind) => {
    statusEl.textContent = text || "";
    statusEl.dataset.kind = kind || "";
  };

  const publishLiveContent = () => {
    host.setLiveContent({
      kind: "list_total",
      item_count: persistedRows(config.rows).length,
      total: totalValue(config.rows),
      total_suffix: config.totalSuffix || null,
      score: autoscore(config),
    });
  };

  const renderTotal = () => {
    const total = totalValue(config.rows);
    totalEl.textContent = `${total.toLocaleString()}${config.totalSuffix || ""}`;
    publishLiveContent();
  };

  const persist = async () => {
    clearSaveTimer();
    busy = true;
    setStatus("Saving", "ok");
    try {
      const nextState = configState(config);
      await host.replaceState(nextState);
      config = normalizeConfig(nextState);
      setStatus("", "");
    } catch (error) {
      console.error("List total card save failed", error);
      setStatus("Unavailable", "error");
    } finally {
      busy = false;
      render();
    }
  };

  const schedulePersist = () => {
    clearSaveTimer();
    saveTimer = window.setTimeout(() => {
      void persist();
    }, 280);
  };

  const normalizeRowsAfterBlur = () => {
    config.rows = ensureTrailingBlankRow(persistedRows(config.rows));
    render();
    schedulePersist();
  };

  const renderRows = () => {
    rowsEl.innerHTML = "";
    config.rows.forEach((row, index) => {
      const rowEl = document.createElement("div");
      rowEl.className = "list-total-card-ui__row";

      const valueInput = document.createElement("input");
      valueInput.className = "list-total-card-ui__input list-total-card-ui__value";
      valueInput.type = "text";
      valueInput.inputMode = "numeric";
      valueInput.maxLength = config.maxDigits;
      valueInput.placeholder = "0";
      valueInput.value = row.value;
      valueInput.disabled = busy;

      const nameInput = document.createElement("input");
      nameInput.className = "list-total-card-ui__input list-total-card-ui__name";
      nameInput.type = "text";
      nameInput.placeholder = "Item";
      nameInput.value = row.name;
      nameInput.disabled = busy;

      valueInput.addEventListener("input", () => {
        config.rows[index].value = sanitizeValue(valueInput.value, config.maxDigits);
        valueInput.value = config.rows[index].value;
        if (index === config.rows.length - 1 && !isBlankRow(config.rows[index])) {
          config.rows = ensureTrailingBlankRow(config.rows);
          render();
          schedulePersist();
          return;
        }
        renderTotal();
        schedulePersist();
      });

      nameInput.addEventListener("input", () => {
        config.rows[index].name = sanitizeName(nameInput.value);
        nameInput.value = config.rows[index].name;
        if (index === config.rows.length - 1 && !isBlankRow(config.rows[index])) {
          config.rows = ensureTrailingBlankRow(config.rows);
          render();
          schedulePersist();
          return;
        }
        renderTotal();
        schedulePersist();
      });

      valueInput.addEventListener("blur", normalizeRowsAfterBlur);
      nameInput.addEventListener("blur", normalizeRowsAfterBlur);

      rowEl.append(valueInput, nameInput);
      rowsEl.appendChild(rowEl);
    });
  };

  const render = () => {
    leftLabelEl.textContent = config.leftLabel;
    rightLabelEl.textContent = config.rightLabel;
    totalLabelEl.textContent = config.totalLabel;
    renderRows();
    renderTotal();
  };

  host.setRefreshHandler(() => {
    config.rows = ensureTrailingBlankRow(config.rows);
    render();
  });

  render();

  return {
    update({ state: nextState }) {
      config = normalizeConfig(nextState);
      render();
    },
    destroy() {
      clearSaveTimer();
      host.setRefreshHandler(null);
      host.setLiveContent(null);
    },
  };
}
