// Parse a JSON-valued settings row.
//
// `settings.value` is TEXT (db/schema.sql), so every JSON-shaped key —
// hero_layout, and now theme_visual / brand_assets / nav_* — is stored
// stringified and arrives as a string. Consumers must parse it, and the parse
// has to be fail-safe: a malformed or wrong-shaped value is treated as
// **absent** (the surface falls back to its BRAND_* env / theme.css / NAV
// default), never as an error and never as a half-applied object. That is the
// same posture parseLayout already takes on the client
// (client/src/lib/heroLayout.js).
//
// See docs/website/THEMING_AND_NAV.md §4.4.

/**
 * @param {string|null|undefined} str  the raw stored value
 * @param {(value: unknown) => boolean} [validator]  shape check; anything it
 *   rejects is treated as absent
 * @returns {object|null} the parsed object, or null when absent/malformed
 */
function parseJsonSetting(str, validator) {
  if (typeof str !== 'string' || str === '') return null
  let parsed
  try {
    parsed = JSON.parse(str)
  } catch {
    return null
  }
  // Only plain objects. A stored `null`, `4`, `"x"` or array is as unusable to
  // every consumer of these keys as a syntax error is.
  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return null
  if (validator && !validator(parsed)) return null
  return parsed
}

module.exports = { parseJsonSetting }
