import { AUTO_SKIP_AT_FIELDS_LS, AUTO_SKIP_VALIDATED_ROWS_LS, BDM_ACT_RECTS_LS, BDM_AUTO_ZOOM_LS, DICT_AUTOCORRECT_ON_LOAD_LS, DEFAULT_SHORTCUT_BINDINGS, FIELD_ORDERS_DEFAULTS_LS, FIELD_ORDERS_LS, FIELD_SELECTIONS_DEFAULTS_LS, FIELD_SELECTIONS_LS, FONT_SCALE_LS, FORM_MIN, FORM_WIDTH_LS, HIGHLIGHT_FLASH_MODE_LS, IMAGES_PANEL_COLLAPSED_LS, INDIVIDUAL_NUMBER_AUTO_INCREMENT_DEFAULT_LS, INDIVIDUAL_NUMBER_AUTO_INCREMENT_LS, KEYBOARD_SHORTCUT_BINDINGS_LS, LAST_BATCH_IMAGES_LS, LAST_BATCH_LS, MERGE_HWR_ORIG_COLUMN_LS, RECT_AUTO_ZOOM_LS, SHORTCUTS_PANEL_STARTUP_LS, SHOW_CONF_COLUMN_LS, SHOW_LOT_ASSIGNMENT_PROMPT_LS, SHOW_MERGED_HWR_TEXT_LS, SIDEBAR_WIDTH_LS, SNIPPET_TOGGLE_MODE_LS, SUGGEST_RANKING_MODE_LS, THEME_LS, USER_PREFS_SAVE_DEBOUNCE_MS } from '../config/constants.js';
import { $ } from '../core/dom.js';
import { api } from '../core/api.js';
import { readLs, writeLs } from '../core/storage.js';
import { getDefaultIndividualNumberAutoIncrement, loadSavedFieldOrderDefaults, loadSavedFieldSelectionDefaults, mergeFieldOrdersFromParsed, mergeFieldSelectionsFromParsed } from './field-selections.js';
import { state, userPrefsStore, runtime } from '../state/app-state.js';
import { syncRectAutoZoomToggleUi, syncRectFlashToggleUi, syncSnippetToggleUi } from '../ui/highlight.js';
import { getBdmAutoZoomEnabled, setBdmAutoZoomEnabled, syncBdmActsToggleUi } from '../ui/image-viewer.js';
import { applyLayoutColumns, maxFormWidth, readSidebarWidth, sidebarWidthClamped, syncImagesPanelToggleUi } from '../ui/layout.js';
import { syncShortcutsStartupOptionUi } from '../ui/settings/panel.js';
import { renderShortcutLists } from '../ui/shortcuts.js';
import { applyFontScale, applyTheme } from '../ui/theme.js';

export function scheduleUserPreferencesSave(patch) {
  if (!patch || typeof patch !== "object") return;
  Object.assign(userPrefsStore, patch);
  if (!runtime.userPrefsHydrated) return;
  clearTimeout(runtime.userPrefsSaveTimer);
  runtime.userPrefsSaveTimer = setTimeout(() => {
    runtime.userPrefsSaveTimer = null;
    void persistUserPreferencesToServer(null, { silent: true });
  }, USER_PREFS_SAVE_DEBOUNCE_MS);
}

/** @returns {Record<string, string>} */
export function getLastBatchImagesMap() {
  const fromStore = userPrefsStore.last_batch_images;
  if (fromStore && typeof fromStore === "object") {
    return Object.fromEntries(
      Object.entries(fromStore)
        .map(([batch, imageId]) => [String(batch || "").trim(), String(imageId || "").trim()])
        .filter(([batch, imageId]) => batch.length > 0 && imageId.length > 0)
    );
  }
  try {
    const raw = readLs(LAST_BATCH_IMAGES_LS);
    if (!raw) return {};
    const parsed = JSON.parse(raw);
    if (!parsed || typeof parsed !== "object") return {};
    return Object.fromEntries(
      Object.entries(parsed)
        .map(([batch, imageId]) => [String(batch || "").trim(), String(imageId || "").trim()])
        .filter(([batch, imageId]) => batch.length > 0 && imageId.length > 0)
    );
  } catch (_) {
    return {};
  }
}

/**
 * Remember the last viewed image for one batch (localStorage + server preferences).
 * @param {string} batchName
 * @param {string|number|null|undefined} imageId
 */
export function rememberLastBatchImage(batchName, imageId) {
  const batch = String(batchName || "").trim();
  const image = imageId == null ? "" : String(imageId).trim();
  if (!batch || !image) return;
  const map = getLastBatchImagesMap();
  if (map[batch] === image) return;
  map[batch] = image;
  userPrefsStore.last_batch_images = map;
  writeLs(LAST_BATCH_IMAGES_LS, JSON.stringify(map));
  scheduleUserPreferencesSave({ last_batch_images: map });
}

/**
 * Anciennes pages sans #imgPan : on enveloppe #pageImg pour zoom/pan.
 * Sans #mainLayout / #splitResizer : on rattache les ids pour la grille.
 */

export function updateFieldSelectionSaveButton() {
  const btn = $("btnSaveFieldSelections");
  if (!btn) return;
  btn.disabled = !state.fieldSelectionsDirty;
}


export function markFieldSelectionsDirty() {
  state.fieldSelectionsDirty = true;
  const feedback = $("fieldsSaveFeedback");
  if (feedback) feedback.textContent = "";
  updateFieldSelectionSaveButton();
}


export function syncIndividualNumberAutoIncrementUi() {
  const checkbox = $("optAutoIncrementIndividualNumber");
  if (!checkbox) return;
  checkbox.checked = !!state.individualNumberAutoIncrement;
}


export function syncAutoSkipValidatedRowsUi() {
  const checkbox = $("optAutoSkipValidatedRows");
  if (!checkbox) return;
  checkbox.checked = !!state.autoSkipValidatedRows;
}


export function syncAutoSkipAtFieldsUi() {
  const checkbox = $("optAutoSkipAtFields");
  if (!checkbox) return;
  checkbox.checked = !!state.autoSkipAtFields;
}


export function syncDictAutocorrectOnLoadUi() {
  const checkbox = $("optDictAutocorrectOnLoad");
  if (!checkbox) return;
  checkbox.checked = !!state.dictAutocorrectOnLoad;
}


export function applyFieldPreferencesPayload(payload) {
  const defaults = loadSavedFieldSelectionDefaults(payload && payload.selections_defaults);
  const defaultOrders = loadSavedFieldOrderDefaults(payload && payload.field_orders_defaults);
  state.fieldSelectionDefaults = { ...defaults };
  state.fieldOrderDefaults = { ...defaultOrders };
  state.individualNumberAutoIncrementDefault = getDefaultIndividualNumberAutoIncrement(
    payload && payload.individual_number_auto_increment_default
  );
  const parsed = payload && payload.selections;
  const parsedOrders = payload && payload.field_orders;
  state.fieldSelections = mergeFieldSelectionsFromParsed({ ...defaults }, parsed);
  state.fieldOrders = mergeFieldOrdersFromParsed({ ...defaultOrders }, parsedOrders);
  if (payload && payload.individual_number_auto_increment != null) {
    state.individualNumberAutoIncrement = !!payload.individual_number_auto_increment;
  } else {
    const rawAutoIncrement = readLs(INDIVIDUAL_NUMBER_AUTO_INCREMENT_LS);
    state.individualNumberAutoIncrement = rawAutoIncrement == null
      ? state.individualNumberAutoIncrementDefault
      : rawAutoIncrement === "1";
  }
  state.fieldSelectionsDirty = false;
  syncIndividualNumberAutoIncrementUi();
  updateFieldSelectionSaveButton();
}


export function initFieldSelectionsFromDefaults() {
  applyFieldPreferencesPayload(null);
}


export function buildFieldPreferencesPayload(includeDefaults) {
  const payload = {
    selections: state.fieldSelections,
    field_orders: state.fieldOrders,
    individual_number_auto_increment: !!state.individualNumberAutoIncrement,
  };
  if (includeDefaults) {
    payload.selections_defaults = state.fieldSelections;
    payload.field_orders_defaults = state.fieldOrders;
    payload.individual_number_auto_increment_default = !!state.individualNumberAutoIncrement;
  }
  return payload;
}


export function mirrorFieldPreferencesToLocalStorage(includeDefaults) {
  writeLs(FIELD_SELECTIONS_LS, JSON.stringify(state.fieldSelections));
  writeLs(FIELD_ORDERS_LS, JSON.stringify(state.fieldOrders));
  writeLs(
    INDIVIDUAL_NUMBER_AUTO_INCREMENT_LS,
    state.individualNumberAutoIncrement ? "1" : "0"
  );
  if (includeDefaults) {
    writeLs(FIELD_SELECTIONS_DEFAULTS_LS, JSON.stringify(state.fieldSelections));
    writeLs(FIELD_ORDERS_DEFAULTS_LS, JSON.stringify(state.fieldOrders));
    writeLs(
      INDIVIDUAL_NUMBER_AUTO_INCREMENT_DEFAULT_LS,
      state.individualNumberAutoIncrement ? "1" : "0"
    );
  }
}


export function readFieldPreferencesFromLocalStorage() {
  try {
    const raw = readLs(FIELD_SELECTIONS_LS);
    if (!raw) return null;
    const parsed = JSON.parse(raw);
    const parsedOrders = readLs(FIELD_ORDERS_LS);
    const parsedDefaults = readLs(FIELD_SELECTIONS_DEFAULTS_LS);
    const parsedOrderDefaults = readLs(FIELD_ORDERS_DEFAULTS_LS);
    const rawAutoIncrement = readLs(INDIVIDUAL_NUMBER_AUTO_INCREMENT_LS);
    const rawAutoIncrementDefault = readLs(INDIVIDUAL_NUMBER_AUTO_INCREMENT_DEFAULT_LS);
    return {
      selections: parsed,
      field_orders: parsedOrders ? JSON.parse(parsedOrders) : {},
      selections_defaults: parsedDefaults ? JSON.parse(parsedDefaults) : {},
      field_orders_defaults: parsedOrderDefaults ? JSON.parse(parsedOrderDefaults) : {},
      individual_number_auto_increment:
        rawAutoIncrement == null ? null : rawAutoIncrement === "1",
      individual_number_auto_increment_default:
        rawAutoIncrementDefault == null ? null : rawAutoIncrementDefault === "1",
    };
  } catch (_) {
    return null;
  }
}


export function readAllPreferencesFromLocalStorage() {
  const payload = readFieldPreferencesFromLocalStorage() || {};
  const theme = readLs(THEME_LS);
  if (theme === "light" || theme === "dark" || theme === "system") payload.theme = theme;
  const fontRaw = readLs(FONT_SCALE_LS);
  if (fontRaw != null) {
    const fontScale = parseFloat(fontRaw);
    if (isFinite(fontScale)) payload.font_scale = fontScale;
  }
  const sidebarRaw = readLs(SIDEBAR_WIDTH_LS);
  if (sidebarRaw != null) {
    const sidebarWidth = parseInt(sidebarRaw, 10);
    if (Number.isFinite(sidebarWidth)) payload.sidebar_width = sidebarWidth;
  }
  const formRaw = readLs(FORM_WIDTH_LS);
  if (formRaw != null) {
    const formWidth = parseInt(formRaw, 10);
    if (Number.isFinite(formWidth)) payload.form_width = formWidth;
  }
  const lastBatch = (readLs(LAST_BATCH_LS) || "").trim();
  if (lastBatch) payload.last_batch = lastBatch;
  try {
    const rawLastImages = readLs(LAST_BATCH_IMAGES_LS);
    if (rawLastImages) {
      const parsedLastImages = JSON.parse(rawLastImages);
      if (parsedLastImages && typeof parsedLastImages === "object") {
        payload.last_batch_images = parsedLastImages;
      }
    }
  } catch (_) {
    /* ignore */
  }
  payload.images_panel_collapsed = readLs(IMAGES_PANEL_COLLAPSED_LS) === "1";
  if (readLs(BDM_AUTO_ZOOM_LS) === "1") payload.bdm_auto_zoom = true;
  if (readLs(BDM_AUTO_ZOOM_LS) === "0") payload.bdm_auto_zoom = false;
  if (readLs(BDM_ACT_RECTS_LS) === "1") payload.bdm_act_rects = true;
  if (readLs(BDM_ACT_RECTS_LS) === "0") payload.bdm_act_rects = false;
  payload.auto_skip_validated_rows = readLs(AUTO_SKIP_VALIDATED_ROWS_LS) === "1";
  payload.auto_skip_at_fields = readLs(AUTO_SKIP_AT_FIELDS_LS) === "1";
  payload.dict_autocorrect_on_load = readLs(DICT_AUTOCORRECT_ON_LOAD_LS) === "1";
  payload.shortcuts_panel_startup = readLs(SHORTCUTS_PANEL_STARTUP_LS) !== "0";
  payload.show_conf_column = readLs(SHOW_CONF_COLUMN_LS) === "1";
  payload.merge_hwr_orig_column = readLs(MERGE_HWR_ORIG_COLUMN_LS) === "1";
  payload.show_merged_hwr_text = readLs(SHOW_MERGED_HWR_TEXT_LS) === "1";
  payload.show_lot_assignment_prompt = readLs(SHOW_LOT_ASSIGNMENT_PROMPT_LS) !== "0";
  const ranking = String(readLs(SUGGEST_RANKING_MODE_LS) || "").trim();
  if (ranking === "frequency_only" || ranking === "recency_only" || ranking === "hybrid") {
    payload.suggest_ranking_mode = ranking;
  }
  payload.highlight_flash_mode = readLs(HIGHLIGHT_FLASH_MODE_LS) === "1";
  payload.rect_auto_zoom = readLs(RECT_AUTO_ZOOM_LS) !== "0";
  payload.snippet_enabled = readLs(SNIPPET_TOGGLE_MODE_LS) !== "0";
  try {
    const rawShortcuts = readLs(KEYBOARD_SHORTCUT_BINDINGS_LS);
    if (rawShortcuts) {
      const parsedShortcuts = JSON.parse(rawShortcuts);
      if (parsedShortcuts && typeof parsedShortcuts === "object") {
        payload.keyboard_shortcut_bindings = parsedShortcuts;
      }
    }
  } catch (_) {
    /* ignore */
  }
  return payload;
}


export function preferencesPayloadHasData(payload) {
  if (!payload || typeof payload !== "object") return false;
  const keys = Object.keys(payload).filter((k) => k !== "updated_at");
  if (!keys.length) return false;
  return keys.some((key) => {
    const value = payload[key];
    if (value == null) return false;
    if (typeof value === "object") return Object.keys(value).length > 0;
    if (typeof value === "string") return value.trim().length > 0;
    return true;
  });
}


export function buildAllUserPreferencesPayload(includeFieldDefaults) {
  const payload = Object.assign({}, buildFieldPreferencesPayload(includeFieldDefaults), {
    theme: runtime.themeMode,
    font_scale: state.uiFontScale,
    sidebar_width: state.sidebarWidthPx != null ? state.sidebarWidthPx : readSidebarWidth(),
    form_width: state.formWidthPx,
    images_panel_collapsed: !!state.imagesPanelCollapsed,
    last_batch: String(state.batch || state.preferredLastBatch || "").trim(),
    last_batch_images: getLastBatchImagesMap(),
    bdm_auto_zoom: getBdmAutoZoomEnabled(),
    bdm_act_rects: !!state.bdmActsEnabled,
    auto_skip_validated_rows: !!state.autoSkipValidatedRows,
    auto_skip_at_fields: !!state.autoSkipAtFields,
    dict_autocorrect_on_load: !!state.dictAutocorrectOnLoad,
    shortcuts_panel_startup: !!state.showShortcutsOnStartup,
    show_conf_column: !!state.showConfColumn,
    merge_hwr_orig_column: !!state.mergeHwrOrigColumn,
    show_merged_hwr_text: !!state.showMergedHwrText,
    show_lot_assignment_prompt: !!state.showLotAssignmentPrompt,
    suggest_ranking_mode: state.suggestRankingMode || "hybrid",
    highlight_flash_mode: !!state.highlightFlashMode,
    rect_auto_zoom: !!state.rectAutoZoomEnabled,
    snippet_enabled: !!state.snippetEnabled,
    keyboard_shortcut_bindings: runtime.shortcutBindingsOverrides,
  });
  return payload;
}


export function applyAllUserPreferences(payload) {
  if (!payload || typeof payload !== "object") return;
  Object.assign(userPrefsStore, payload);
  applyFieldPreferencesPayload(payload);
  if (payload.theme === "light" || payload.theme === "dark" || payload.theme === "system") {
    applyTheme(payload.theme);
  }
  if (payload.font_scale != null) applyFontScale(payload.font_scale);
  if (payload.images_panel_collapsed != null) {
    state.imagesPanelCollapsed = !!payload.images_panel_collapsed;
    applyLayoutColumns();
    syncImagesPanelToggleUi();
  }
  if (payload.last_batch) state.preferredLastBatch = String(payload.last_batch).trim();
  if (payload.last_batch_images && typeof payload.last_batch_images === "object") {
    const cleaned = Object.fromEntries(
      Object.entries(payload.last_batch_images)
        .map(([batch, imageId]) => [String(batch || "").trim(), String(imageId || "").trim()])
        .filter(([batch, imageId]) => batch.length > 0 && imageId.length > 0)
    );
    userPrefsStore.last_batch_images = cleaned;
    writeLs(LAST_BATCH_IMAGES_LS, JSON.stringify(cleaned));
  }
  if (payload.bdm_auto_zoom != null) setBdmAutoZoomEnabled(!!payload.bdm_auto_zoom);
  if (payload.bdm_act_rects != null) state.bdmActsEnabled = !!payload.bdm_act_rects;
  if (payload.auto_skip_validated_rows != null) {
    state.autoSkipValidatedRows = !!payload.auto_skip_validated_rows;
    syncAutoSkipValidatedRowsUi();
  }
  if (payload.auto_skip_at_fields != null) {
    state.autoSkipAtFields = !!payload.auto_skip_at_fields;
    syncAutoSkipAtFieldsUi();
  }
  if (payload.dict_autocorrect_on_load != null) {
    state.dictAutocorrectOnLoad = !!payload.dict_autocorrect_on_load;
    syncDictAutocorrectOnLoadUi();
  }
  if (payload.shortcuts_panel_startup != null) {
    state.showShortcutsOnStartup = !!payload.shortcuts_panel_startup;
    syncShortcutsStartupOptionUi();
  }
  if (payload.show_conf_column != null) {
    state.showConfColumn = !!payload.show_conf_column;
    syncShowConfColumnUi();
  }
  if (payload.merge_hwr_orig_column != null) {
    state.mergeHwrOrigColumn = !!payload.merge_hwr_orig_column;
    syncMergeHwrOrigColumnUi();
  }
  if (payload.show_merged_hwr_text != null) {
    state.showMergedHwrText = !!payload.show_merged_hwr_text;
    syncShowMergedHwrTextUi();
  }
  if (payload.show_lot_assignment_prompt != null) {
    state.showLotAssignmentPrompt = !!payload.show_lot_assignment_prompt;
    syncShowLotAssignmentPromptUi();
  }
  if (
    payload.suggest_ranking_mode === "frequency_only" ||
    payload.suggest_ranking_mode === "recency_only" ||
    payload.suggest_ranking_mode === "hybrid"
  ) {
    state.suggestRankingMode = payload.suggest_ranking_mode;
    syncSuggestRankingModeUi();
  }
  if (payload.highlight_flash_mode != null) {
    state.highlightFlashMode = !!payload.highlight_flash_mode;
    syncRectFlashToggleUi();
  }
  if (payload.rect_auto_zoom != null) {
    state.rectAutoZoomEnabled = !!payload.rect_auto_zoom;
    syncRectAutoZoomToggleUi();
  }
  if (payload.snippet_enabled != null) {
    state.snippetEnabled = !!payload.snippet_enabled;
    syncSnippetToggleUi();
  }
  if (payload.keyboard_shortcut_bindings && typeof payload.keyboard_shortcut_bindings === "object") {
    runtime.shortcutBindingsOverrides = {};
    Object.keys(DEFAULT_SHORTCUT_BINDINGS).forEach((id) => {
      const o = payload.keyboard_shortcut_bindings[id];
      if (!o || typeof o !== "object") return;
      const code = typeof o.code === "string" ? o.code : "";
      if (!code) return;
      const key = typeof o.key === "string" ? o.key.trim().toLowerCase() : "";
      runtime.shortcutBindingsOverrides[id] = {
        ctrl: !!o.ctrl,
        alt: !!o.alt,
        shift: !!o.shift,
        meta: !!o.meta,
        code,
        ...(key.length === 1 && /^[a-z0-9]$/.test(key) ? { key } : {}),
      };
    });
    renderShortcutLists();
  }
  if (payload.sidebar_width != null) {
    state.sidebarWidthPx = sidebarWidthClamped(Number(payload.sidebar_width));
    applyLayoutColumns();
  }
  if (payload.form_width != null) {
    const fw = parseInt(String(payload.form_width), 10);
    if (Number.isFinite(fw)) {
      state.formWidthPx = Math.max(FORM_MIN, Math.min(maxFormWidth(), fw));
      applyLayoutColumns();
    }
  }
  syncBdmActsToggleUi();
  runtime.userPrefsHydrated = true;
}


export async function loadUserPreferencesFromServer() {
  try {
    const remote = await api("/api/user-preferences");
    if (preferencesPayloadHasData(remote)) {
      applyAllUserPreferences(remote);
      return;
    }
    const localPayload = readAllPreferencesFromLocalStorage();
    if (preferencesPayloadHasData(localPayload)) {
      applyAllUserPreferences(localPayload);
      await persistUserPreferencesToServer(null, { silent: true });
      return;
    }
    runtime.userPrefsHydrated = true;
  } catch (_) {
    const localPayload = readAllPreferencesFromLocalStorage();
    if (preferencesPayloadHasData(localPayload)) applyAllUserPreferences(localPayload);
    else runtime.userPrefsHydrated = true;
  }
}


export async function persistUserPreferencesToServer(patch, options) {
  const opts = options || {};
  const includeFieldDefaults = !!opts.includeDefaults;
  const payload = Object.assign(
    {},
    buildAllUserPreferencesPayload(includeFieldDefaults),
    patch || {}
  );
  mirrorFieldPreferencesToLocalStorage(includeFieldDefaults);
  if (payload.theme === "light" || payload.theme === "dark" || payload.theme === "system") {
    writeLs(THEME_LS, payload.theme);
  }
  if (payload.font_scale != null) writeLs(FONT_SCALE_LS, String(payload.font_scale));
  if (payload.sidebar_width != null) writeLs(SIDEBAR_WIDTH_LS, String(payload.sidebar_width));
  if (payload.form_width != null) writeLs(FORM_WIDTH_LS, String(payload.form_width));
  if (payload.last_batch) writeLs(LAST_BATCH_LS, payload.last_batch);
  writeLs(LAST_BATCH_IMAGES_LS, JSON.stringify(getLastBatchImagesMap()));
  writeLs(IMAGES_PANEL_COLLAPSED_LS, payload.images_panel_collapsed ? "1" : "0");
  writeLs(BDM_AUTO_ZOOM_LS, payload.bdm_auto_zoom ? "1" : "0");
  writeLs(BDM_ACT_RECTS_LS, payload.bdm_act_rects ? "1" : "0");
  writeLs(AUTO_SKIP_VALIDATED_ROWS_LS, payload.auto_skip_validated_rows ? "1" : "0");
  writeLs(AUTO_SKIP_AT_FIELDS_LS, payload.auto_skip_at_fields ? "1" : "0");
  writeLs(DICT_AUTOCORRECT_ON_LOAD_LS, payload.dict_autocorrect_on_load ? "1" : "0");
  writeLs(SHORTCUTS_PANEL_STARTUP_LS, payload.shortcuts_panel_startup ? "1" : "0");
  writeLs(SHOW_CONF_COLUMN_LS, payload.show_conf_column ? "1" : "0");
  writeLs(MERGE_HWR_ORIG_COLUMN_LS, payload.merge_hwr_orig_column ? "1" : "0");
  writeLs(SHOW_MERGED_HWR_TEXT_LS, payload.show_merged_hwr_text ? "1" : "0");
  writeLs(SHOW_LOT_ASSIGNMENT_PROMPT_LS, payload.show_lot_assignment_prompt ? "1" : "0");
  writeLs(SUGGEST_RANKING_MODE_LS, payload.suggest_ranking_mode || "hybrid");
  writeLs(HIGHLIGHT_FLASH_MODE_LS, payload.highlight_flash_mode ? "1" : "0");
  writeLs(RECT_AUTO_ZOOM_LS, payload.rect_auto_zoom ? "1" : "0");
  writeLs(SNIPPET_TOGGLE_MODE_LS, payload.snippet_enabled ? "1" : "0");
  const shortcutKeys = Object.keys(payload.keyboard_shortcut_bindings || {});
  if (!shortcutKeys.length) writeLs(KEYBOARD_SHORTCUT_BINDINGS_LS, null);
  else writeLs(KEYBOARD_SHORTCUT_BINDINGS_LS, JSON.stringify(payload.keyboard_shortcut_bindings));
  Object.assign(userPrefsStore, payload);
  try {
    await api("/api/user-preferences", {
      method: "PUT",
      body: JSON.stringify(payload),
    });
  } catch (e) {
    if (!opts.silent) throw e;
  }
  state.fieldSelectionsDirty = false;
  updateFieldSelectionSaveButton();
}


export async function loadFieldSelectionsFromServer() {
  await loadUserPreferencesFromServer();
}


export async function persistFieldPreferences(options) {
  const opts = options || {};
  await persistUserPreferencesToServer(buildFieldPreferencesPayload(!!opts.includeDefaults), opts);
}


export async function saveCurrentSelectionsAsDefaults() {
  state.fieldSelectionDefaults = { ...state.fieldSelections };
  state.fieldOrderDefaults = Object.fromEntries(
    Object.entries(state.fieldOrders || {}).map(([key, order]) => [
      key,
      Array.isArray(order) ? [...order] : [],
    ])
  );
  state.individualNumberAutoIncrementDefault = !!state.individualNumberAutoIncrement;
  await persistFieldPreferences({ includeDefaults: true });
}


export function loadShortcutsPanelStartupPreference() {
  if (userPrefsStore.shortcuts_panel_startup != null) {
    state.showShortcutsOnStartup = !!userPrefsStore.shortcuts_panel_startup;
    return;
  }
  state.showShortcutsOnStartup = readLs(SHORTCUTS_PANEL_STARTUP_LS) !== "0";
}


export function loadShowConfColumnPreference() {
  if (userPrefsStore.show_conf_column != null) {
    state.showConfColumn = !!userPrefsStore.show_conf_column;
    return;
  }
  state.showConfColumn = readLs(SHOW_CONF_COLUMN_LS) === "1";
}


export function loadMergeHwrOrigColumnPreference() {
  if (userPrefsStore.merge_hwr_orig_column != null) {
    state.mergeHwrOrigColumn = !!userPrefsStore.merge_hwr_orig_column;
    return;
  }
  state.mergeHwrOrigColumn = readLs(MERGE_HWR_ORIG_COLUMN_LS) === "1";
}


export function loadShowMergedHwrTextPreference() {
  if (userPrefsStore.show_merged_hwr_text != null) {
    state.showMergedHwrText = !!userPrefsStore.show_merged_hwr_text;
    return;
  }
  state.showMergedHwrText = readLs(SHOW_MERGED_HWR_TEXT_LS) === "1";
}


export function loadShowLotAssignmentPromptPreference() {
  if (userPrefsStore.show_lot_assignment_prompt != null) {
    state.showLotAssignmentPrompt = !!userPrefsStore.show_lot_assignment_prompt;
    return;
  }
  state.showLotAssignmentPrompt = readLs(SHOW_LOT_ASSIGNMENT_PROMPT_LS) !== "0";
}



export function saveShortcutsPanelStartupPreference() {
  writeLs(SHORTCUTS_PANEL_STARTUP_LS, state.showShortcutsOnStartup ? "1" : "0");
  scheduleUserPreferencesSave({ shortcuts_panel_startup: !!state.showShortcutsOnStartup });
}


export function saveShowConfColumnPreference() {
  writeLs(SHOW_CONF_COLUMN_LS, state.showConfColumn ? "1" : "0");
  scheduleUserPreferencesSave({ show_conf_column: !!state.showConfColumn });
}


export function saveMergeHwrOrigColumnPreference() {
  writeLs(MERGE_HWR_ORIG_COLUMN_LS, state.mergeHwrOrigColumn ? "1" : "0");
  scheduleUserPreferencesSave({ merge_hwr_orig_column: !!state.mergeHwrOrigColumn });
}


export function saveShowMergedHwrTextPreference() {
  writeLs(SHOW_MERGED_HWR_TEXT_LS, state.showMergedHwrText ? "1" : "0");
  scheduleUserPreferencesSave({ show_merged_hwr_text: !!state.showMergedHwrText });
}


export function saveShowLotAssignmentPromptPreference() {
  writeLs(SHOW_LOT_ASSIGNMENT_PROMPT_LS, state.showLotAssignmentPrompt ? "1" : "0");
  scheduleUserPreferencesSave({ show_lot_assignment_prompt: !!state.showLotAssignmentPrompt });
}



export function syncShowConfColumnUi() {
  const checked = !!state.showConfColumn;
  const opt = $("optShowConfColumn");
  if (opt) opt.checked = checked;
  const topbar = $("topbarOptShowConfColumn");
  if (topbar) topbar.checked = checked;
}


export function syncMergeHwrOrigColumnUi() {
  const checked = !!state.mergeHwrOrigColumn;
  const opt = $("optMergeHwrOrigColumn");
  if (opt) opt.checked = checked;
  const topbar = $("topbarOptMergeHwrOrigColumn");
  if (topbar) topbar.checked = checked;
  const mergeOff = !checked;
  const hwrOpt = $("optShowMergedHwrText");
  if (hwrOpt) hwrOpt.disabled = mergeOff;
  const topbarHwr = $("topbarOptShowMergedHwrText");
  if (topbarHwr) topbarHwr.disabled = mergeOff;
}


export function syncShowMergedHwrTextUi() {
  const checked = !!state.showMergedHwrText;
  const opt = $("optShowMergedHwrText");
  if (opt) opt.checked = checked;
  const topbar = $("topbarOptShowMergedHwrText");
  if (topbar) topbar.checked = checked;
}


export function syncShowLotAssignmentPromptUi() {
  const checked = !!state.showLotAssignmentPrompt;
  const opt = $("optShowLotAssignmentPrompt");
  if (opt) opt.checked = checked;
}


export function loadSuggestRankingModePreference() {
  const fromStore = String(userPrefsStore.suggest_ranking_mode || "").trim();
  if (fromStore === "frequency_only" || fromStore === "recency_only" || fromStore === "hybrid") {
    state.suggestRankingMode = fromStore;
    return;
  }
  const raw = String(readLs(SUGGEST_RANKING_MODE_LS) || "").trim();
  if (raw === "frequency_only" || raw === "recency_only" || raw === "hybrid") {
    state.suggestRankingMode = raw;
  } else {
    state.suggestRankingMode = "hybrid";
  }
}


export function saveSuggestRankingModePreference() {
  writeLs(SUGGEST_RANKING_MODE_LS, state.suggestRankingMode || "hybrid");
  scheduleUserPreferencesSave({ suggest_ranking_mode: state.suggestRankingMode || "hybrid" });
}


export function syncSuggestRankingModeUi() {
  const sel = $("optSuggestRankingMode");
  if (!sel) return;
  sel.value = state.suggestRankingMode || "hybrid";
}
