///|
fn Worksheet::ensure_stream_idle(self : Worksheet) -> Unit raise XlsxError {
  if self.stream_state != Idle {
    raise StreamModeConflict(msg="worksheet is in stream writer mode")
  }
}

///|
fn Worksheet::sorted_cells(self : Worksheet) -> Array[Cell] {
  let sorted : Array[Cell] = []
  for cell in self.cells {
    sorted.push(cell)
  }
  sort_cells(sorted)
  sorted
}

///|
fn parse_range_ref(
  range_ref : StringView,
) -> (Int, Int, Int, Int) raise XlsxError {
  let parts : Array[String] = []
  for part in range_ref.split(":") {
    parts.push(part.to_owned())
  }
  if parts.length() == 1 {
    let (row, col) = cell_ref_to_rc(parts[0])
    return (row, col, row, col)
  }
  if parts.length() != 2 {
    raise InvalidCellRef(value=range_ref.to_owned())
  }
  let (row1, col1) = cell_ref_to_rc(parts[0])
  let (row2, col2) = cell_ref_to_rc(parts[1])
  let min_row = if row1 < row2 { row1 } else { row2 }
  let max_row = if row1 > row2 { row1 } else { row2 }
  let min_col = if col1 < col2 { col1 } else { col2 }
  let max_col = if col1 > col2 { col1 } else { col2 }
  (min_row, min_col, max_row, max_col)
}

///|
fn normalize_range_ref(range_ref : StringView) -> String raise XlsxError {
  let (min_row, min_col, max_row, max_col) = parse_range_ref(range_ref)
  let start_ref = cell_ref_from(min_row, min_col)
  let end_ref = cell_ref_from(max_row, max_col)
  "\{start_ref}:\{end_ref}"
}

///|
fn cell_in_bounds(
  row : Int,
  col : Int,
  min_row : Int,
  min_col : Int,
  max_row : Int,
  max_col : Int,
) -> Bool {
  row >= min_row && row <= max_row && col >= min_col && col <= max_col
}

///|
fn bounds_contain(
  outer : (Int, Int, Int, Int),
  inner : (Int, Int, Int, Int),
) -> Bool {
  let (outer_min_row, outer_min_col, outer_max_row, outer_max_col) = outer
  let (inner_min_row, inner_min_col, inner_max_row, inner_max_col) = inner
  inner_min_row >= outer_min_row &&
  inner_min_col >= outer_min_col &&
  inner_max_row <= outer_max_row &&
  inner_max_col <= outer_max_col
}

///|
fn normalize_cell_or_range_ref(
  reference : StringView,
) -> String raise XlsxError {
  if reference.contains(":") {
    normalize_range_ref(reference)
  } else {
    let (row, col) = cell_ref_to_rc(reference)
    cell_ref_from(row, col)
  }
}

///|
fn cell_in_reference(
  reference : StringView,
  row : Int,
  col : Int,
) -> Bool raise XlsxError {
  if reference.contains(":") {
    let (min_row, min_col, max_row, max_col) = parse_range_ref(reference)
    cell_in_bounds(row, col, min_row, min_col, max_row, max_col)
  } else {
    let (target_row, target_col) = cell_ref_to_rc(reference)
    target_row == row && target_col == col
  }
}

///|
fn Worksheet::merged_anchor_for_cell(
  self : Worksheet,
  row : Int,
  col : Int,
) -> String? raise XlsxError {
  for range_ref in self.merged_cells {
    let (min_row, min_col, max_row, max_col) = parse_range_ref(range_ref)
    if cell_in_bounds(row, col, min_row, min_col, max_row, max_col) {
      return Some(cell_ref_from(min_row, min_col))
    }
  }
  None
}

///|
fn Worksheet::hyperlink_anchor_for_cell(
  self : Worksheet,
  row : Int,
  col : Int,
) -> String raise XlsxError {
  match self.merged_anchor_for_cell(row, col) {
    Some(value) => value
    None => cell_ref_from(row, col)
  }
}

///|
/// Writes `value` into the cell at `reference` (A1 notation, e.g. `"B2"`) as a
/// raw string, overwriting any existing content while preserving the cell's
/// style. For numeric or boolean values use `set_cell_value`; for dates and
/// times use `Workbook::set_cell_time`; for formulas use `set_cell_formula`.
///
/// Raises `XlsxError` if `reference` is not a valid A1 cell reference, or
/// `StreamModeConflict` if the worksheet is currently driven by a stream
/// writer.
pub fn Worksheet::set_cell(
  self : Worksheet,
  reference : String,
  value : String,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  self.invalidate_shared_formula_masters_index()
  let (row, col) = cell_ref_to_rc(reference)
  let canonical = cell_ref_from(row, col)
  match self.cell_index_of(row, col) {
    Some(i) => {
      let style_id = self.cells[i].style_id
      self.cells[i] = {
        reference: canonical,
        row,
        col,
        value,
        value_type: String,
        rich_text: None,
        formula: None,
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: false,
        style_explicit: self.cells[i].style_explicit,
        style_id,
      }
    }
    None => {
      let index = self.cells.length()
      self.cells.push({
        reference: canonical,
        row,
        col,
        value,
        value_type: String,
        rich_text: None,
        formula: None,
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: false,
        style_explicit: false,
        style_id: 0,
      })
      self.record_cell_index_if_valid(row, col, index)
    }
  }
}

///|
/// Returns the raw string value of the cell at `reference` (A1 notation), or
/// `None` if the cell has never been set. Numbers and booleans are returned in
/// their stored string form; use `get_cell_value_raw` to recover the typed
/// `CellValue` instead.
///
/// Raises `XlsxError` if `reference` is not a valid A1 cell reference.
pub fn Worksheet::get_cell(
  self : Worksheet,
  reference : StringView,
) -> String? raise XlsxError {
  let (row, col) = cell_ref_to_rc(reference)
  match self.cell_index_of(row, col) {
    Some(i) => Some(self.cells[i].value)
    None => None
  }
}

///|
/// Writes a typed `CellValue` (number, string, boolean, …) into the cell at
/// `reference` (A1 notation), overwriting existing content while preserving the
/// cell's style. Prefer this over `set_cell` when the value should be stored as
/// a number or boolean rather than as text (so Excel treats it numerically).
///
/// Raises `XlsxError` if `reference` is not a valid A1 cell reference, or
/// `StreamModeConflict` if the worksheet is currently driven by a stream
/// writer.
pub fn Worksheet::set_cell_value(
  self : Worksheet,
  reference : String,
  value : CellValue,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  self.invalidate_shared_formula_masters_index()
  let (row, col) = cell_ref_to_rc(reference)
  let canonical = cell_ref_from(row, col)
  let value_type = cell_value_type(value)
  let raw_value = cell_value_raw_string(value)
  match self.cell_index_of(row, col) {
    Some(i) => {
      let style_id = self.cells[i].style_id
      self.cells[i] = {
        reference: canonical,
        row,
        col,
        value: raw_value,
        value_type,
        rich_text: None,
        formula: None,
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: false,
        style_explicit: self.cells[i].style_explicit,
        style_id,
      }
    }
    None => {
      let index = self.cells.length()
      self.cells.push({
        reference: canonical,
        row,
        col,
        value: raw_value,
        value_type,
        rich_text: None,
        formula: None,
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: false,
        style_explicit: false,
        style_id: 0,
      })
      self.record_cell_index_if_valid(row, col, index)
    }
  }
}

///|
/// Returns the typed `CellValue` stored at `reference` (A1 notation), or `None`
/// if the cell has never been set. Unlike `get_cell`, this preserves the value
/// type (number vs. text vs. boolean) rather than coercing to a string.
///
/// Raises `XlsxError` if `reference` is not a valid A1 cell reference.
pub fn Worksheet::get_cell_value_raw(
  self : Worksheet,
  reference : StringView,
) -> CellValue? raise XlsxError {
  let (row, col) = cell_ref_to_rc(reference)
  match self.cell_index_of(row, col) {
    Some(i) =>
      Some(cell_value_from_raw(self.cells[i].value_type, self.cells[i].value))
    None => None
  }
}

///|
fn Worksheet::get_cell_type(
  self : Worksheet,
  reference : StringView,
) -> CellValueType? raise XlsxError {
  match self.get_cell_value_raw(reference) {
    Some(value) => Some(cell_value_type(value))
    None => None
  }
}

///|
pub fn Worksheet::set_auto_filter(
  self : Worksheet,
  range_ref : String,
  options : ArrayView[AutoFilterOption],
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let filter = auto_filter_from_options(range_ref, options)
  self.auto_filter = Some(filter)
}

///|
pub fn Worksheet::clear_auto_filter(self : Worksheet) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  self.auto_filter = None
}

///|
pub fn Worksheet::set_cell_rich_text(
  self : Worksheet,
  reference : String,
  runs : ArrayView[RichTextRun],
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  self.invalidate_shared_formula_masters_index()
  let total = rich_text_total_units(runs)
  if total > max_cell_chars {
    raise CellTextTooLong(len=total)
  }
  let (row, col) = cell_ref_to_rc(reference)
  let canonical = cell_ref_from(row, col)
  let stored_runs : Array[RichTextRun] = []
  for run in runs {
    stored_runs.push(run)
  }
  let value = rich_text_plain_text(runs)
  match self.cell_index_of(row, col) {
    Some(i) => {
      let style_id = self.cells[i].style_id
      self.cells[i] = {
        reference: canonical,
        row,
        col,
        value,
        value_type: String,
        rich_text: Some(stored_runs),
        formula: None,
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: false,
        style_explicit: self.cells[i].style_explicit,
        style_id,
      }
    }
    None => {
      let index = self.cells.length()
      self.cells.push({
        reference: canonical,
        row,
        col,
        value,
        value_type: String,
        rich_text: Some(stored_runs),
        formula: None,
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: false,
        style_explicit: false,
        style_id: 0,
      })
      self.record_cell_index_if_valid(row, col, index)
    }
  }
}

///|
pub fn Worksheet::get_cell_rich_text(
  self : Worksheet,
  reference : StringView,
) -> Array[RichTextRun]? raise XlsxError {
  let (row, col) = cell_ref_to_rc(reference)
  match self.cell_index_of(row, col) {
    Some(i) => {
      let cell = self.cells[i]
      if cell.value_type != String {
        None
      } else {
        match cell.rich_text {
          Some(runs) => {
            let copied : Array[RichTextRun] = []
            for run in runs {
              copied.push(run)
            }
            Some(copied)
          }
          None => {
            let runs : Array[RichTextRun] = []
            runs.push({ text: cell.value, font: None })
            Some(runs)
          }
        }
      }
    }
    None => None
  }
}

///|
/// The A1 references of every cell on this sheet that carries a **non-empty**
/// formula, in stored order. A small primitive for tools that need to visit
/// the formula cells (e.g. a formula lint) without scanning the whole grid —
/// the set of formula cells is usually far smaller than the used range.
///
/// A shared-formula *slave* stores an empty formula string (the master holds
/// the text) and is not independently evaluable, so it is excluded — visiting
/// one would only mislead a caller that evaluates the formula.
pub fn Worksheet::formula_refs(self : Worksheet) -> Array[String] {
  let refs = []
  for cell in self.cells {
    match cell.formula {
      Some(formula) if formula != "" => refs.push(cell.reference)
      _ => ()
    }
  }
  refs
}

///|
/// Indexes and validates one worksheet's shared-formula groups. Followers are
/// omitted from the returned map, so master formula text and its copy anchor
/// are retained only once even for large shared ranges.
fn shared_formula_validation_checkpoint(
  budget : ReadBudget?,
  cancelled : () -> Bool,
) -> Unit raise XlsxError {
  match budget {
    Some(value) => value.checkpoint()
    None => if cancelled() { raise ReadCancelled }
  }
}

///|
fn validated_shared_formula_masters(
  cells : ArrayView[Cell],
  budget? : ReadBudget,
  cancelled? : () -> Bool = () => false,
) -> Map[UInt, SharedFormulaMaster] raise XlsxError {
  let masters : Map[UInt, SharedFormulaMaster] = Map([])
  shared_formula_validation_checkpoint(budget, cancelled)
  match budget {
    Some(value) => value.charge_work(cells.length())
    None => ()
  }
  let mut cell_index = 0
  for cell in cells {
    if (cell_index & 4095) == 0 {
      shared_formula_validation_checkpoint(budget, cancelled)
    }
    match
      (
        cell.formula_type,
        cell.formula,
        cell.formula_shared_index,
        cell.formula_ref,
      ) {
      (Some(Shared), Some(formula), Some(shared_index), Some(range_ref)) => {
        if formula == "" {
          raise InvalidXml(msg="shared formula master text missing")
        }
        let (row_lo, column_lo, row_hi, column_hi) = parse_range_ref(range_ref)
        if cell.row < row_lo ||
          cell.row > row_hi ||
          cell.col < column_lo ||
          cell.col > column_hi {
          raise InvalidXml(msg="shared formula master is outside its range")
        }
        let master : SharedFormulaMaster = {
          formula,
          row: cell.row,
          column: cell.col,
          row_lo,
          column_lo,
          row_hi,
          column_hi,
        }
        match masters.get(shared_index) {
          Some(_) =>
            raise InvalidXml(msg="shared formula index has conflicting masters")
          None => masters[shared_index] = master
        }
      }
      (Some(Shared), Some(_), None, _) =>
        raise InvalidXml(msg="shared formula index missing")
      (Some(Shared), None, _, _) =>
        raise InvalidXml(msg="shared formula text missing")
      _ => ()
    }
    cell_index += 1
  }
  // ISO/IEC 29500 says master ranges on one sheet should not overlap, but
  // Excel itself has emitted overlapping ranges for distinct shared indices.
  // Formula cells carry an explicit `si`, so group membership remains
  // unambiguous. Keep tolerant reads group-local: duplicate masters for one
  // index were rejected above, and every follower is checked against that
  // index's own master below. Writers are unaffected by this input tolerance.
  shared_formula_validation_checkpoint(budget, cancelled)
  match budget {
    Some(value) => value.charge_work(cells.length())
    None => ()
  }
  cell_index = 0
  for cell in cells {
    if (cell_index & 4095) == 0 {
      shared_formula_validation_checkpoint(budget, cancelled)
    }
    match (cell.formula_type, cell.formula_shared_index, cell.formula_ref) {
      (Some(Shared), Some(shared_index), None) =>
        match masters.get(shared_index) {
          Some(master) =>
            if !master.contains_coordinate(cell.row, cell.col) {
              raise InvalidXml(
                msg="shared formula follower is outside the master range",
              )
            }
          None => raise InvalidXml(msg="shared formula follower has no master")
        }
      _ => ()
    }
    cell_index += 1
  }
  shared_formula_validation_checkpoint(budget, cancelled)
  masters
}

///|
fn clone_shared_formula_masters_index(
  source : Map[UInt, SharedFormulaMaster],
) -> Map[UInt, SharedFormulaMaster] {
  let cloned : Map[UInt, SharedFormulaMaster] = Map([])
  for shared_index, master in source {
    cloned[shared_index] = master
  }
  cloned
}

///|
/// Counts only the shared cells an edit will retain or copy, then performs one
/// aggregate fan-out check before the first translated string is allocated.
fn preflight_shared_formula_materialization(
  cells : ArrayView[Cell],
  masters : Map[UInt, SharedFormulaMaster],
  budget : SharedFormulaMaterializationBudget,
  retain : (Cell) -> Bool,
) -> Unit raise XlsxError {
  let formula_counts : Map[UInt, Int] = Map([])
  budget.checkpoint()
  let mut cell_index = 0
  for cell in cells {
    if (cell_index & 4095) == 0 {
      budget.checkpoint()
    }
    if retain(cell) {
      match (cell.formula_type, cell.formula_shared_index) {
        (Some(Shared), Some(shared_index)) => {
          let current = formula_counts.get(shared_index).unwrap_or(0)
          let (next, exceeded) = read_budget_actual(current, 1, 0x7fffffff)
          if exceeded {
            raise ResourceLimitExceeded(
              kind="shared_formula_followers",
              limit=0x7fffffff,
              actual=next,
            )
          }
          formula_counts[shared_index] = next
        }
        (Some(Shared), None) =>
          raise InvalidXml(msg="shared formula index missing")
        _ => ()
      }
    }
    cell_index += 1
  }
  budget.preflight(formula_counts, masters)
}

///|
/// Converts one shared-formula cell to an independent normal formula before a
/// structural edit moves or duplicates it. Shared ranges are metadata over
/// fixed coordinates; retaining that metadata while coordinates change makes
/// the group internally inconsistent. Materializing each cell preserves the
/// formula represented at its original coordinate and makes subsequent cell
/// movement follow the same rules as every other normal formula.
fn normal_formula_cell_for_structural_edit(
  cell : Cell,
  masters : Map[UInt, SharedFormulaMaster],
  budget : SharedFormulaMaterializationBudget,
) -> Cell raise XlsxError {
  match (cell.formula_type, cell.formula_shared_index) {
    (Some(Shared), Some(shared_index)) => {
      let master = match masters.get(shared_index) {
        Some(value) => value
        None => raise InvalidXml(msg="shared formula cell has no master")
      }
      {
        reference: cell.reference,
        row: cell.row,
        col: cell.col,
        value: cell.value,
        value_type: cell.value_type,
        rich_text: cell.rich_text,
        formula: Some(budget.translate(master, cell.row, cell.col)),
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: cell.formula_value_present,
        style_explicit: cell.style_explicit,
        style_id: cell.style_id,
      }
    }
    _ => cell
  }
}

///|
fn Worksheet::invalidate_shared_formula_masters_index(self : Worksheet) -> Unit {
  self.shared_formula_masters_index.clear()
  self.shared_formula_masters_index_valid = false
}

///|
fn Worksheet::ensure_shared_formula_masters_index(
  self : Worksheet,
  cancelled? : () -> Bool = () => false,
) -> Unit raise XlsxError {
  if cancelled() {
    raise ReadCancelled
  }
  if self.shared_formula_masters_index_valid {
    return
  }
  let rebuilt = validated_shared_formula_masters(self.cells, cancelled~)
  self.shared_formula_masters_index.clear()
  let mut master_index = 0
  for shared_index, master in rebuilt {
    if (master_index & 4095) == 0 && cancelled() {
      self.shared_formula_masters_index.clear()
      raise ReadCancelled
    }
    self.shared_formula_masters_index[shared_index] = master
    master_index += 1
  }
  if cancelled() {
    self.shared_formula_masters_index.clear()
    raise ReadCancelled
  }
  self.shared_formula_masters_index_valid = true
}

///|
/// Returns non-empty shared-formula masters keyed by OOXML shared index after
/// validating that every follower has exactly one master and lies within the
/// master's declared range. Conflicting or incomplete groups are rejected.
pub fn Worksheet::shared_formula_masters(
  self : Worksheet,
) -> Map[UInt, SharedFormulaMaster] raise XlsxError {
  self.ensure_shared_formula_masters_index()
  clone_shared_formula_masters_index(self.shared_formula_masters_index)
}

///|
/// Looks up one validated shared-formula master without cloning the complete
/// master index. Parsed worksheets already carry an eagerly validated index;
/// programmatically edited worksheets rebuild it lazily before this lookup.
/// `cancelled` is polled while rebuilding a stale index.
pub fn Worksheet::shared_formula_master(
  self : Worksheet,
  shared_index : UInt,
  cancelled? : () -> Bool = () => false,
) -> SharedFormulaMaster? raise XlsxError {
  self.ensure_shared_formula_masters_index(cancelled~)
  self.shared_formula_masters_index.get(shared_index)
}

///|
test "shared formula masters stay eagerly indexed after bounded read" {
  let source = Workbook::new()
  let source_sheet = source.add_sheet("Data")
  source_sheet.set_cell_formula_opts(
    "A1",
    "C1+1",
    opts=FormulaOpts::shared("A1:A2"),
  )
  let parsed = read(write(source))
  guard parsed.sheet("Data") is Some(sheet) else {
    fail("expected parsed shared-formula worksheet")
  }
  assert_true(sheet.shared_formula_masters_index_valid)
  assert_eq(sheet.shared_formula_masters_index.length(), 1)
  let exported = sheet.shared_formula_masters()
  exported.clear()
  assert_eq(sheet.shared_formula_masters_index.length(), 1)
  assert_true(sheet.shared_formula_master(0) is Some(_))
}

///|
test "cell mutation invalidates and safely rebuilds shared formula index" {
  let sheet = Worksheet::new("Data")
  sheet.set_cell_formula_opts("A1", "C1+1", opts=FormulaOpts::shared("A1:A2"))
  assert_false(sheet.shared_formula_masters_index_valid)
  assert_eq(sheet.shared_formula_masters().length(), 1)
  assert_true(sheet.shared_formula_masters_index_valid)
  sheet.set_cell("D1", "value")
  assert_false(sheet.shared_formula_masters_index_valid)
  assert_eq(sheet.shared_formula_masters().length(), 1)
}

///|
pub fn Worksheet::set_cell_formula(
  self : Worksheet,
  reference : String,
  formula : String,
  value? : String = "",
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  self.invalidate_shared_formula_masters_index()
  let (row, col) = cell_ref_to_rc(reference)
  let canonical = cell_ref_from(row, col)
  match self.cell_index_of(row, col) {
    Some(i) => {
      let style_id = self.cells[i].style_id
      self.cells[i] = {
        reference: canonical,
        row,
        col,
        value,
        value_type: String,
        rich_text: None,
        formula: Some(formula),
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: value != "",
        style_explicit: self.cells[i].style_explicit,
        style_id,
      }
    }
    None => {
      let index = self.cells.length()
      self.cells.push({
        reference: canonical,
        row,
        col,
        value,
        value_type: String,
        rich_text: None,
        formula: Some(formula),
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: value != "",
        style_explicit: false,
        style_id: 0,
      })
      self.record_cell_index_if_valid(row, col, index)
    }
  }
}

///|
pub fn Worksheet::get_cell_formula(
  self : Worksheet,
  reference : StringView,
) -> String? raise XlsxError {
  let (row, col) = cell_ref_to_rc(reference)
  match self.cell_index_of(row, col) {
    Some(i) =>
      match self.cells[i].formula {
        Some(value) => if value == "" { None } else { Some(value) }
        None => None
      }
    None => None
  }
}

///|
/// Returns the stored formula metadata for a 1-based coordinate without
/// collapsing an empty shared-formula follower to `None`.
///
/// This complements `get_cell_formula`, whose compatibility contract returns
/// only independently stored, non-empty formula text. The returned formula is
/// not translated from a shared master; `shared_index` identifies that master
/// when a consumer needs its text.
pub fn Worksheet::get_cell_formula_info_rc(
  self : Worksheet,
  row : Int,
  col : Int,
) -> CellFormulaInfo? raise XlsxError {
  ignore(cell_ref_from(row, col))
  match self.cell_index_of(row, col) {
    Some(i) =>
      match self.cells[i].formula {
        Some(formula) =>
          Some({
            formula,
            formula_type: self.cells[i].formula_type,
            range_ref: self.cells[i].formula_ref,
            shared_index: self.cells[i].formula_shared_index,
            cached_value_present: self.cells[i].formula_value_present,
          })
        None => None
      }
    None => None
  }
}

///|
pub fn Worksheet::set_cell_formula_opts(
  self : Worksheet,
  reference : String,
  formula : String,
  opts? : FormulaOpts = FormulaOpts::new(),
  value? : String = "",
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  self.invalidate_shared_formula_masters_index()
  let formula_kind = opts.formula_type
  match formula_kind {
    None => self.set_cell_formula(reference, formula, value~)
    Some(Normal) => self.set_cell_formula(reference, formula, value~)
    Some(DataTable) => self.set_cell_formula(reference, formula, value~)
    Some(Array) => {
      let range_ref = match opts.range_ref {
        Some(value) => normalize_range_ref(value)
        None => raise InvalidSheetOperation(msg="array formula ref missing")
      }
      let (min_row, min_col, max_row, max_col) = parse_range_ref(range_ref)
      let (master_row, master_col) = cell_ref_to_rc(reference)
      let canonical_master = cell_ref_from(master_row, master_col)
      if canonical_master != cell_ref_from(min_row, min_col) {
        raise InvalidSheetOperation(
          msg="array formula master must be top-left of ref",
        )
      }
      fn set_formula_cell(
        sheet : Worksheet,
        row : Int,
        col : Int,
        formula : String,
        formula_ref : String,
        value : String,
      ) -> Unit raise XlsxError {
        let canonical = cell_ref_from(row, col)
        match sheet.cell_index_of(row, col) {
          Some(i) => {
            let style_id = sheet.cells[i].style_id
            sheet.cells[i] = {
              reference: canonical,
              row,
              col,
              value,
              value_type: String,
              rich_text: None,
              formula: Some(formula),
              formula_type: Some(Array),
              formula_ref: Some(formula_ref),
              formula_shared_index: None,
              formula_value_present: value != "",
              style_explicit: sheet.cells[i].style_explicit,
              style_id,
            }
          }
          None => {
            let index = sheet.cells.length()
            sheet.cells.push({
              reference: canonical,
              row,
              col,
              value,
              value_type: String,
              rich_text: None,
              formula: Some(formula),
              formula_type: Some(Array),
              formula_ref: Some(formula_ref),
              formula_shared_index: None,
              formula_value_present: value != "",
              style_explicit: false,
              style_id: 0,
            })
            sheet.record_cell_index_if_valid(row, col, index)
          }
        }
      }
      for row in min_row..<=max_row {
        for col in min_col..<=max_col {
          if row == min_row && col == min_col {
            set_formula_cell(self, row, col, formula, range_ref, value)
          } else {
            set_formula_cell(self, row, col, "", range_ref, "")
          }
        }
      }
    }
    Some(Shared) => {
      let range_ref = match opts.range_ref {
        Some(value) => normalize_range_ref(value)
        None => raise InvalidSheetOperation(msg="shared formula ref missing")
      }
      let (min_row, min_col, max_row, max_col) = parse_range_ref(range_ref)
      let (master_row, master_col) = cell_ref_to_rc(reference)
      let canonical_master = cell_ref_from(master_row, master_col)
      if canonical_master != cell_ref_from(min_row, min_col) {
        raise InvalidSheetOperation(
          msg="shared formula master must be top-left of ref",
        )
      }
      let mut max_si : UInt? = None
      for cell in self.cells {
        match cell.formula_shared_index {
          Some(si) =>
            match max_si {
              Some(current) => if si > current { max_si = Some(si) }
              None => max_si = Some(si)
            }
          None => ()
        }
      }
      let shared_index = match max_si {
        Some(0xFFFFFFFF) =>
          raise InvalidSheetOperation(msg="shared formula index exhausted")
        Some(value) => value + 1
        None => 0
      }
      fn set_shared_cell(
        sheet : Worksheet,
        row : Int,
        col : Int,
        formula : String,
        formula_ref : String?,
        shared_index : UInt,
        value : String,
      ) -> Unit raise XlsxError {
        let canonical = cell_ref_from(row, col)
        match sheet.cell_index_of(row, col) {
          Some(i) => {
            let style_id = sheet.cells[i].style_id
            sheet.cells[i] = {
              reference: canonical,
              row,
              col,
              value,
              value_type: String,
              rich_text: None,
              formula: Some(formula),
              formula_type: Some(Shared),
              formula_ref,
              formula_shared_index: Some(shared_index),
              formula_value_present: value != "",
              style_explicit: sheet.cells[i].style_explicit,
              style_id,
            }
          }
          None => {
            let index = sheet.cells.length()
            sheet.cells.push({
              reference: canonical,
              row,
              col,
              value,
              value_type: String,
              rich_text: None,
              formula: Some(formula),
              formula_type: Some(Shared),
              formula_ref,
              formula_shared_index: Some(shared_index),
              formula_value_present: value != "",
              style_explicit: false,
              style_id: 0,
            })
            sheet.record_cell_index_if_valid(row, col, index)
          }
        }
      }
      for row in min_row..<=max_row {
        for col in min_col..<=max_col {
          if row == min_row && col == min_col {
            set_shared_cell(
              self,
              row,
              col,
              formula,
              Some(range_ref),
              shared_index,
              value,
            )
          } else {
            set_shared_cell(self, row, col, "", None, shared_index, "")
          }
        }
      }
    }
  }
}

///|
/// Sets or replaces the hyperlink identified by `reference`. Cells inside a
/// merged range use its top-left anchor as their shared identity. `External`
/// targets accept the documented safe URI schemes or forward-slash relative
/// paths; `Location` targets reject explicit URI schemes. Empty, XML-illegal,
/// unsafe-scheme, and backslash-form external targets raise `InvalidHyperlink`
/// before mutation. Passing `Unset` removes the anchored hyperlink.
pub fn Worksheet::set_cell_hyperlink(
  self : Worksheet,
  reference : String,
  target : String,
  link_type : HyperlinkType,
  display? : String = "",
  tooltip? : String = "",
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let (row, col) = cell_ref_to_rc(reference)
  let resolved = self.hyperlink_anchor_for_cell(row, col)
  if link_type == Unset {
    self.remove_cell_hyperlink(resolved)
    return
  }
  validate_hyperlink_values(target, link_type, display, tooltip)
  let display_value = if display == "" { None } else { Some(display) }
  let tooltip_value = if tooltip == "" { None } else { Some(tooltip) }
  let normalized_ref = normalize_cell_or_range_ref(resolved)
  let mut existing_index : Int? = None
  for i, link in self.hyperlinks {
    if link.reference == normalized_ref {
      existing_index = Some(i)
      break
    }
  }
  let next : Hyperlink = {
    reference: normalized_ref,
    target,
    link_type,
    location: if link_type == Location {
      Some(target)
    } else {
      None
    },
    display: display_value,
    tooltip: tooltip_value,
  }
  match existing_index {
    Some(index) => self.hyperlinks[index] = next
    None => {
      if self.hyperlinks.length() >= max_sheet_hyperlinks {
        raise HyperlinkLimitExceeded(limit=max_sheet_hyperlinks)
      }
      self.hyperlinks.push(next)
    }
  }
}

///|
pub fn Worksheet::set_cell_hyperlink_opts(
  self : Worksheet,
  reference : String,
  target : String,
  link_type : HyperlinkType,
  opts? : HyperlinkOpts = HyperlinkOpts::new(),
) -> Unit raise XlsxError {
  let display = match opts.display {
    Some(value) => value
    None => ""
  }
  let tooltip = match opts.tooltip {
    Some(value) => value
    None => ""
  }
  self.set_cell_hyperlink(reference, target, link_type, display~, tooltip~)
}

///|
pub fn Worksheet::get_cell_hyperlink(
  self : Worksheet,
  reference : StringView,
) -> Hyperlink? raise XlsxError {
  let (row, col) = cell_ref_to_rc(reference)
  let resolved = self.hyperlink_anchor_for_cell(row, col)
  let (resolved_row, resolved_col) = cell_ref_to_rc(resolved)
  for link in self.hyperlinks {
    if cell_in_reference(link.reference, resolved_row, resolved_col) {
      return Some(link)
    }
  }
  None
}

///|
/// Returns full hyperlink records in worksheet XML/insertion order. References
/// are canonical A1 cell/range references. Omitting `link_type` returns every
/// hyperlink; `External` and `Location` filter by hyperlink kind; `Unset`
/// returns no records.
pub fn Worksheet::get_hyperlinks(
  self : Worksheet,
  link_type? : HyperlinkType,
) -> Array[Hyperlink] {
  let links : Array[Hyperlink] = []
  for link in self.hyperlinks {
    if hyperlink_matches_type(link, link_type) {
      links.push(link)
    }
  }
  links
}

///|
/// Returns the cell references of hyperlinks in the worksheet, mirroring
/// Excelize's `GetHyperLinkCells`. Omitting `link_type` returns every
/// hyperlink; `External` and `Location` filter by hyperlink kind; `Unset`
/// (Excelize's "None") returns no references.
pub fn Worksheet::get_hyperlink_cells(
  self : Worksheet,
  link_type? : HyperlinkType,
) -> Array[String] {
  let references : Array[String] = []
  for link in self.get_hyperlinks(link_type?) {
    references.push(link.reference)
  }
  references
}

///|
pub fn Worksheet::remove_cell_hyperlink(
  self : Worksheet,
  reference : StringView,
) -> Unit raise XlsxError {
  let (row, col) = cell_ref_to_rc(reference)
  let resolved = self.hyperlink_anchor_for_cell(row, col)
  let (resolved_row, resolved_col) = cell_ref_to_rc(resolved)
  let updated : Array[Hyperlink] = []
  for link in self.hyperlinks {
    if cell_in_reference(link.reference, resolved_row, resolved_col) {
      continue
    }
    updated.push(link)
  }
  self.hyperlinks.clear()
  self.hyperlinks.append(updated)
}

///|
fn Worksheet::comment_index(self : Worksheet, cell : String) -> Int? {
  for index, comment in self.comments {
    if comment.cell == cell {
      return Some(index)
    }
  }
  None
}

///|
/// Adds a classic cell comment. The cell must not already have a comment, and
/// the complete record is validated without truncation before mutation.
pub fn Worksheet::add_comment(
  self : Worksheet,
  comment : Comment,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let normalized = normalize_comment(comment)
  if self.comment_index(normalized.cell) is Some(_) {
    raise CommentAlreadyExists(cell=normalized.cell)
  }
  self.comments.push(normalized)
}

///|
/// Replaces the existing classic comment at `comment.cell` without changing
/// comment enumeration order. The complete replacement is validated before
/// mutation.
pub fn Worksheet::replace_comment(
  self : Worksheet,
  comment : Comment,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let normalized = normalize_comment(comment)
  match self.comment_index(normalized.cell) {
    Some(index) => self.comments[index] = normalized
    None => raise CommentNotFound(cell=normalized.cell)
  }
}

///|
/// Returns the classic comment anchored at `cell`, if one exists.
pub fn Worksheet::get_comment(
  self : Worksheet,
  cell : StringView,
) -> Comment? raise XlsxError {
  let (row, col) = cell_ref_to_rc(cell)
  let canonical = cell_ref_from(row, col)
  match self.comment_index(canonical) {
    Some(index) => Some(clone_comment(self.comments[index]))
    None => None
  }
}

///|
/// Deletes the classic comment anchored at `cell`.
pub fn Worksheet::delete_comment(
  self : Worksheet,
  cell : StringView,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let (row, col) = cell_ref_to_rc(cell)
  let canonical = cell_ref_from(row, col)
  let updated : Array[Comment] = []
  let mut found = false
  for entry in self.comments {
    if entry.cell == canonical {
      found = true
      continue
    }
    updated.push(entry)
  }
  if !found {
    raise CommentNotFound(cell=canonical)
  }
  let next_vml_drawing_xml = match self.vml_drawing_xml {
    Some(xml) => Some(remove_vml_comment_shapes_at_cell(xml, canonical))
    None => None
  }
  self.comments.clear()
  self.comments.append(updated)
  self.vml_drawing_xml = next_vml_drawing_xml
}

///|
pub fn Worksheet::set_cell_style(
  self : Worksheet,
  reference : String,
  style_id : Int,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if style_id < 0 {
    raise InvalidStyleId(index=style_id)
  }
  let (row, col) = cell_ref_to_rc(reference)
  let canonical = cell_ref_from(row, col)
  match self.cell_index_of(row, col) {
    Some(i) => {
      let cell = self.cells[i]
      self.cells[i] = {
        reference: canonical,
        row,
        col,
        value: cell.value,
        value_type: cell.value_type,
        rich_text: cell.rich_text,
        formula: cell.formula,
        formula_type: cell.formula_type,
        formula_ref: cell.formula_ref,
        formula_shared_index: cell.formula_shared_index,
        formula_value_present: cell.formula_value_present,
        style_explicit: true,
        style_id,
      }
    }
    None => {
      let index = self.cells.length()
      self.cells.push({
        reference: canonical,
        row,
        col,
        value: "",
        value_type: String,
        rich_text: None,
        formula: None,
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: false,
        style_explicit: true,
        style_id,
      })
      self.record_cell_index_if_valid(row, col, index)
    }
  }
}

///|
pub fn Worksheet::get_cell_style(
  self : Worksheet,
  reference : StringView,
) -> Int? raise XlsxError {
  let (row, col) = cell_ref_to_rc(reference)
  match self.cell_index_of(row, col) {
    Some(i) => Some(self.cells[i].style_id)
    None => None
  }
}

///|
pub fn Worksheet::set_cell_style_rc(
  self : Worksheet,
  row : Int,
  col : Int,
  style_id : Int,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if style_id < 0 {
    raise InvalidStyleId(index=style_id)
  }
  let reference = cell_ref_from(row, col)
  match self.cell_index_of(row, col) {
    Some(i) => {
      let cell = self.cells[i]
      self.cells[i] = {
        reference,
        row,
        col,
        value: cell.value,
        value_type: cell.value_type,
        rich_text: cell.rich_text,
        formula: cell.formula,
        formula_type: cell.formula_type,
        formula_ref: cell.formula_ref,
        formula_shared_index: cell.formula_shared_index,
        formula_value_present: cell.formula_value_present,
        style_explicit: true,
        style_id,
      }
    }
    None => {
      let index = self.cells.length()
      self.cells.push({
        reference,
        row,
        col,
        value: "",
        value_type: String,
        rich_text: None,
        formula: None,
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: false,
        style_explicit: true,
        style_id,
      })
      self.record_cell_index_if_valid(row, col, index)
    }
  }
}

///|
pub fn Worksheet::get_cell_style_rc(
  self : Worksheet,
  row : Int,
  col : Int,
) -> Int? raise XlsxError {
  if row <= 0 || col <= 0 {
    raise InvalidCellRef(value="\{col}:\{row}")
  }
  match self.cell_index_of(row, col) {
    Some(i) => Some(self.cells[i].style_id)
    None => None
  }
}

///|
/// Returns the style that formats a resolved coordinate without performing a
/// workbook sheet-name lookup. Precedence matches the write path: an explicit
/// cell style (including style 0) wins, then the row style, then the column
/// style, then style 0.
/// The row and column are 1-based and must fit the XLSX grid.
pub fn Worksheet::effective_style_id_rc(
  self : Worksheet,
  row : Int,
  col : Int,
) -> Int raise XlsxError {
  ignore(cell_ref_from(row, col))
  match self.cell_index_of(row, col) {
    Some(i) if self.cells[i].style_explicit => self.cells[i].style_id
    _ =>
      match self.get_row_style(row) {
        Some(style_id) => style_id
        None =>
          match self.get_col_style(col) {
            Some(style_id) => style_id
            None => 0
          }
      }
  }
}

///|
/// Merges the rectangular range `range_ref` (e.g. `"A1:C3"`) into a single
/// region; the top-left cell's value is displayed across the whole range. The
/// range is normalized, so `"C3:A1"` and `"A1:C3"` are equivalent.
///
/// Raises `XlsxError` if `range_ref` is not a valid range reference.
pub fn Worksheet::merge_cells(
  self : Worksheet,
  range_ref : String,
) -> Unit raise XlsxError {
  let normalized = normalize_range_ref(range_ref)
  for existing in self.merged_cells {
    if existing == normalized {
      return
    }
  }
  let merge_bounds = parse_range_ref(normalized)
  let (min_row, min_col, _, _) = merge_bounds
  let anchor = cell_ref_from(min_row, min_col)
  match plan_hyperlinks_for_merge(self.hyperlinks, merge_bounds) {
    Keep => ()
    Reanchor(index) => reanchor_hyperlink(self.hyperlinks, index, anchor)
    Conflict(msg) =>
      raise InvalidSheetOperation(msg="cannot merge cells: \{msg}")
  }
  self.merged_cells.push(normalized)
}

///|
pub fn Worksheet::unmerge_cells(
  self : Worksheet,
  range_ref : String,
) -> Unit raise XlsxError {
  let normalized = normalize_range_ref(range_ref)
  for i, existing in self.merged_cells {
    if existing == normalized {
      ignore(self.merged_cells.remove(i))
      return
    }
  }
}

///|
pub fn Worksheet::add_table(
  self : Worksheet,
  range_ref : String,
  name : String,
  columns : ArrayView[String],
  display_name? : String = "",
  style_name? : String = "TableStyleMedium9",
  show_first_column? : Bool = false,
  show_last_column? : Bool = false,
  show_row_stripes? : Bool = true,
  show_column_stripes? : Bool = false,
  show_header_row? : Bool = true,
) -> Table raise XlsxError {
  let table = Table::new(
    name,
    range_ref,
    columns,
    display_name~,
    style_name~,
    show_first_column~,
    show_last_column~,
    show_row_stripes~,
    show_column_stripes~,
    show_header_row~,
  )
  self.tables.push(table)
  table
}

///|
pub fn Worksheet::delete_table(
  self : Worksheet,
  name : StringView,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let updated : Array[Table] = []
  let mut removed = false
  let target = name.to_owned()
  for table in self.tables {
    if table.name == target || table.display_name == target {
      removed = true
      continue
    }
    updated.push(table)
  }
  if !removed {
    raise TableNotFound(name=target)
  }
  self.tables.clear()
  self.tables.append(updated)
}

///|
pub fn Worksheet::add_sparkline(
  self : Worksheet,
  location : String,
  range_ref : String,
  sparkline_type? : SparklineType = Line,
) -> Unit raise XlsxError {
  self.add_sparkline_group([location], [range_ref], sparkline_type~)
}

///|
pub fn Worksheet::add_sparkline_group(
  self : Worksheet,
  locations : ArrayView[String],
  ranges : ArrayView[String],
  sparkline_type? : SparklineType = Line,
) -> Unit raise XlsxError {
  if locations.length() == 0 || ranges.length() == 0 {
    raise InvalidSparkline(msg="sparkline inputs empty")
  }
  if locations.length() != ranges.length() {
    raise InvalidSparkline(msg="sparkline inputs mismatch")
  }
  let sparklines = build_sparklines(locations, ranges)
  self.sparkline_groups.push({
    sparkline_type,
    sparklines,
    options: SparklineGroupOptions::new(),
  })
}

///|
pub fn Worksheet::add_sparkline_options(
  self : Worksheet,
  options : SparklineOptions,
) -> Unit raise XlsxError {
  let group = build_sparkline_group_from_options(options)
  self.sparkline_groups.push(group)
}

///|
pub fn Worksheet::add_pivot_table_xml(
  self : Worksheet,
  table_xml : String,
  cache_definition_xml : String,
  cache_records_xml? : String = "",
  name? : String = "",
) -> PivotTable raise XlsxError {
  self.ensure_stream_idle()
  let pivot = PivotTable::new(
    table_xml,
    cache_definition_xml,
    cache_records_xml~,
    name~,
  )
  self.pivot_tables.push(pivot)
  pivot
}

///|
pub fn Worksheet::delete_pivot_table(
  self : Worksheet,
  name : StringView,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let target = name.to_owned()
  if target == "" {
    raise InvalidSheetOperation(msg="pivot table name empty")
  }
  let remaining : Array[PivotTable] = []
  let mut removed = false
  for pivot in self.pivot_tables {
    if pivot.name == target {
      removed = true
    } else {
      remaining.push(pivot)
    }
  }
  if !removed {
    raise InvalidSheetOperation(msg="pivot table not found")
  }
  self.pivot_tables.clear()
  for pivot in remaining {
    self.pivot_tables.push(pivot)
  }
}

///|
fn normalize_extension(extension : StringView) -> String raise XlsxError {
  let value = extension.to_owned()
  let trimmed = match value.strip_prefix(".") {
    Some(rest) => rest.to_owned()
    None => value
  }
  if trimmed == "" {
    raise UnsupportedFeature(msg="image extension missing")
  }
  trimmed
}

///|
fn normalize_extension_lower_requires_dot(
  extension : StringView,
  unsupported_msg : StringView,
) -> String raise XlsxError {
  fn trim_leading_dot(value : StringView) -> String {
    let parts = Array::from_iter(value.split("."))
    let rest : Array[String] = []
    for i, part in parts {
      if i > 0 {
        rest.push(part.to_owned())
      }
    }
    rest.join(".")
  }
  let raw = extension.to_owned()
  if !raw.has_prefix(".") || raw.length() <= 1 {
    raise UnsupportedFeature(msg=unsupported_msg.to_owned())
  }
  let trimmed = trim_leading_dot(raw)
  trimmed.to_lower()
}

///|
fn check_header_footer_image_size(
  value : StringView,
  field_name : StringView,
) -> Unit raise XlsxError {
  if value is "" {
    raise InvalidHeaderFooter(msg="\{field_name.to_owned()} empty")
  }
}

///|
fn normalize_picture_options(
  offset_x : Int,
  offset_y : Int,
  scale_x : Double,
  scale_y : Double,
  hyperlink : String,
  hyperlink_type : HyperlinkType,
) -> (Int, Int, Double, Double, String, HyperlinkType) raise XlsxError {
  if offset_x < 0 || offset_y < 0 {
    raise InvalidSheetOperation(msg="picture offset must be >= 0")
  }
  if scale_x <= 0.0 || scale_y <= 0.0 {
    raise InvalidSheetOperation(msg="picture scale must be > 0")
  }
  if hyperlink == "" {
    return (offset_x, offset_y, scale_x, scale_y, "", Unset)
  }
  if hyperlink_type == Unset {
    raise InvalidHyperlink(msg="picture hyperlink type missing")
  }
  (offset_x, offset_y, scale_x, scale_y, hyperlink, hyperlink_type)
}

///|
let picture_emu_per_pixel = 9525

///|
let default_picture_width_px = 200

///|
let default_picture_height_px = 160

///|
let default_row_height_pixels : Int = convert_row_height_to_pixels(15.0)

///|
let max_graphic_name_length = 254

///|
let max_graphic_alt_text_length = 65535

///|
fn convert_col_width_to_pixels(width : Double) -> Int {
  if width == 0.0 {
    return 0
  }
  let pixels = width * 8.0 + 0.5
  pixels.to_int()
}

///|
fn convert_row_height_to_pixels(height : Double) -> Int {
  if height == 0.0 {
    return 0
  }
  Double::ceil(4.0 / 3.4 * height).to_int()
}

///|
fn Worksheet::default_col_width_pixels(self : Worksheet) -> Int {
  let props = sheet_props_with_defaults(self.sheet_props)
  match props.default_col_width {
    Some(w) => convert_col_width_to_pixels(w)
    None => {
      let base = props.base_col_width.unwrap_or(default_sheet_base_col_width)
      convert_col_width_to_pixels(Double::from_int(base))
    }
  }
}

///|
fn Worksheet::default_row_height_pixels(self : Worksheet) -> Int {
  let props = sheet_props_with_defaults(self.sheet_props)
  match props.default_row_height {
    Some(h) => convert_row_height_to_pixels(h)
    None => default_row_height_pixels
  }
}

///|
fn Worksheet::col_width_pixels(self : Worksheet, col : Int) -> Int {
  match self.col_dimensions.get(col) {
    Some(dim) =>
      if dim.hidden {
        0
      } else {
        match dim.width {
          Some(width) => convert_col_width_to_pixels(width)
          None => self.default_col_width_pixels()
        }
      }
    None => self.default_col_width_pixels()
  }
}

///|
fn Worksheet::row_height_pixels(self : Worksheet, row : Int) -> Int {
  match self.row_dimensions.get(row) {
    Some(dim) =>
      if dim.hidden {
        0
      } else {
        match dim.height {
          Some(height) => convert_row_height_to_pixels(height)
          None => self.default_row_height_pixels()
        }
      }
    None => self.default_row_height_pixels()
  }
}

///|
fn Worksheet::merged_rect_for_cell(
  self : Worksheet,
  row : Int,
  col : Int,
) -> (Int, Int, Int, Int)? raise XlsxError {
  for range_ref in self.merged_cells {
    let (min_row, min_col, max_row, max_col) = parse_range_ref(range_ref)
    if cell_in_bounds(row, col, min_row, min_col, max_row, max_col) {
      return Some((min_row, min_col, max_row, max_col))
    }
  }
  None
}

///|
fn Worksheet::anchor_cell_size_pixels(
  self : Worksheet,
  row : Int,
  col : Int,
) -> (Int, Int, Int, Int) raise XlsxError {
  match self.merged_rect_for_cell(row, col) {
    Some((min_row, min_col, max_row, max_col)) => {
      let mut cell_width = 0
      let mut cell_height = 0
      for c in min_col..<=max_col {
        cell_width = cell_width + self.col_width_pixels(c)
      }
      for r in min_row..<=max_row {
        cell_height = cell_height + self.row_height_pixels(r)
      }
      (min_row, min_col, cell_width, cell_height)
    }
    None => (row, col, self.col_width_pixels(col), self.row_height_pixels(row))
  }
}

///|
pub fn Worksheet::add_header_footer_image(
  self : Worksheet,
  options : HeaderFooterImageOptions,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  match options.file {
    Some(_) =>
      raise InvalidHeaderFooter(
        msg="header/footer image file path requires add_header_footer_image_from_file",
      )
    None => ()
  }
  let extension = normalize_extension_lower_requires_dot(
    options.extension,
    "unsupported header/footer image extension",
  )
  let content_type = match image_content_type(extension) {
    Some(value) => value
    None =>
      raise UnsupportedFeature(msg="unsupported header/footer image extension")
  }
  check_header_footer_image_size(options.width, "header/footer width")
  check_header_footer_image_size(options.height, "header/footer height")
  let image : HeaderFooterImage = {
    position: options.position,
    data: options.data,
    extension,
    content_type,
    is_footer: options.is_footer,
    first_page: options.first_page,
    width: options.width,
    height: options.height,
  }
  let updated : Array[HeaderFooterImage] = []
  for existing in self.header_footer_images {
    if existing.position == image.position &&
      existing.is_footer == image.is_footer &&
      existing.first_page == image.first_page {
      continue
    }
    updated.push(existing)
  }
  updated.push(image)
  self.header_footer_images.clear()
  self.header_footer_images.append(updated)
}

///|
#cfg(target="native")
async fn Worksheet::add_header_footer_image_from_file(
  self : Worksheet,
  options : HeaderFooterImageOptions,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let path = match options.file {
    Some(value) => value
    None =>
      raise InvalidHeaderFooter(msg="header/footer image file path missing")
  }
  let data = read_file_bytes(path) catch {
    err =>
      raise InvalidHeaderFooter(
        msg="read header/footer image failed: \{repr(err)}",
      )
  }
  self.add_header_footer_image(
    HeaderFooterImageOptions::new(
      options.position,
      data,
      options.extension,
      is_footer=options.is_footer,
      first_page=options.first_page,
      width=options.width,
      height=options.height,
    ),
  )
}

///|
fn Worksheet::add_picture_from_bytes(
  self : Worksheet,
  reference : String,
  data : Bytes,
  extension : String,
  offset_x? : Int = 0,
  offset_y? : Int = 0,
  scale_x? : Double = 1.0,
  scale_y? : Double = 1.0,
  hyperlink? : String = "",
  hyperlink_type? : HyperlinkType = Unset,
  name? : String = "",
  alt_text? : String = "",
  lock_aspect_ratio? : Bool = false,
  auto_fit? : Bool = false,
  auto_fit_ignore_aspect? : Bool = false,
  print_object? : Bool = true,
  locked? : Bool = true,
  positioning? : PicturePositioning = OneCell,
) -> Unit raise XlsxError {
  let ext = normalize_extension_lower_requires_dot(
    extension, "unsupported picture extension",
  )
  let content_type = match image_content_type(ext) {
    Some(value) => value
    None => raise UnsupportedFeature(msg="unsupported picture extension")
  }
  self.add_image(
    reference,
    data,
    ext,
    content_type,
    offset_x~,
    offset_y~,
    scale_x~,
    scale_y~,
    hyperlink~,
    hyperlink_type~,
    name~,
    alt_text~,
    lock_aspect_ratio~,
    auto_fit~,
    auto_fit_ignore_aspect~,
    print_object~,
    locked~,
    positioning~,
  )
}

///|
fn Worksheet::add_picture_from_bytes_with_options(
  self : Worksheet,
  reference : String,
  data : Bytes,
  extension : String,
  options : GraphicOptions,
) -> Unit raise XlsxError {
  let offset_x = options.offset_x.unwrap_or(0)
  let offset_y = options.offset_y.unwrap_or(0)
  let scale_x = options.scale_x.unwrap_or(1.0)
  let scale_y = options.scale_y.unwrap_or(1.0)
  let hyperlink = options.hyperlink.unwrap_or("")
  let hyperlink_type = options.hyperlink_type.unwrap_or(Unset)
  let name = options.name.unwrap_or("")
  let alt_text = options.alt_text.unwrap_or("")
  let lock_aspect_ratio = options.lock_aspect_ratio.unwrap_or(false)
  let auto_fit = options.auto_fit.unwrap_or(false)
  let auto_fit_ignore_aspect = options.auto_fit_ignore_aspect.unwrap_or(false)
  let print_object = options.print_object.unwrap_or(true)
  let locked = options.locked.unwrap_or(true)
  let positioning = options.positioning.unwrap_or(OneCell)
  self.add_picture_from_bytes(
    reference,
    data,
    extension,
    offset_x~,
    offset_y~,
    scale_x~,
    scale_y~,
    hyperlink~,
    hyperlink_type~,
    name~,
    alt_text~,
    lock_aspect_ratio~,
    auto_fit~,
    auto_fit_ignore_aspect~,
    print_object~,
    locked~,
    positioning~,
  )
}

///|
#cfg(target="native")
async fn Worksheet::add_picture(
  self : Worksheet,
  reference : String,
  path : String,
  offset_x? : Int = 0,
  offset_y? : Int = 0,
  scale_x? : Double = 1.0,
  scale_y? : Double = 1.0,
  hyperlink? : String = "",
  hyperlink_type? : HyperlinkType = Unset,
  name? : String = "",
  alt_text? : String = "",
  lock_aspect_ratio? : Bool = false,
  auto_fit? : Bool = false,
  auto_fit_ignore_aspect? : Bool = false,
  print_object? : Bool = true,
  locked? : Bool = true,
  positioning? : PicturePositioning = OneCell,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let extension = match extension_from_path(path) {
    Some(value) => value
    None => raise UnsupportedFeature(msg="image extension missing")
  }
  let bytes = read_file_bytes(path) catch {
    err => raise InvalidSheetOperation(msg="read picture failed: \{repr(err)}")
  }
  self.add_picture_from_bytes(
    reference,
    bytes,
    ".\{extension}",
    offset_x~,
    offset_y~,
    scale_x~,
    scale_y~,
    hyperlink~,
    hyperlink_type~,
    name~,
    alt_text~,
    lock_aspect_ratio~,
    auto_fit~,
    auto_fit_ignore_aspect~,
    print_object~,
    locked~,
    positioning~,
  )
}

///|
#cfg(target="native")
async fn Worksheet::add_picture_with_options(
  self : Worksheet,
  reference : String,
  path : String,
  options : GraphicOptions,
) -> Unit raise XlsxError {
  let offset_x = options.offset_x.unwrap_or(0)
  let offset_y = options.offset_y.unwrap_or(0)
  let scale_x = options.scale_x.unwrap_or(1.0)
  let scale_y = options.scale_y.unwrap_or(1.0)
  let hyperlink = options.hyperlink.unwrap_or("")
  let hyperlink_type = options.hyperlink_type.unwrap_or(Unset)
  let name = options.name.unwrap_or("")
  let alt_text = options.alt_text.unwrap_or("")
  let lock_aspect_ratio = options.lock_aspect_ratio.unwrap_or(false)
  let auto_fit = options.auto_fit.unwrap_or(false)
  let auto_fit_ignore_aspect = options.auto_fit_ignore_aspect.unwrap_or(false)
  let print_object = options.print_object.unwrap_or(true)
  let locked = options.locked.unwrap_or(true)
  let positioning = options.positioning.unwrap_or(OneCell)
  self.add_picture(
    reference,
    path,
    offset_x~,
    offset_y~,
    scale_x~,
    scale_y~,
    hyperlink~,
    hyperlink_type~,
    name~,
    alt_text~,
    lock_aspect_ratio~,
    auto_fit~,
    auto_fit_ignore_aspect~,
    print_object~,
    locked~,
    positioning~,
  )
}

///|
pub fn Worksheet::add_image(
  self : Worksheet,
  reference : String,
  data : Bytes,
  extension : String,
  content_type : String,
  offset_x? : Int = 0,
  offset_y? : Int = 0,
  scale_x? : Double = 1.0,
  scale_y? : Double = 1.0,
  hyperlink? : String = "",
  hyperlink_type? : HyperlinkType = Unset,
  name? : String = "",
  alt_text? : String = "",
  lock_aspect_ratio? : Bool = false,
  auto_fit? : Bool = false,
  auto_fit_ignore_aspect? : Bool = false,
  print_object? : Bool = true,
  locked? : Bool = true,
  positioning? : PicturePositioning = OneCell,
) -> Unit raise XlsxError {
  let (row, col) = cell_ref_to_rc(reference)
  let ext = normalize_extension(extension)
  if name != "" && name.length() > max_graphic_name_length {
    raise GraphicNameTooLong(len=name.length(), limit=max_graphic_name_length)
  }
  if alt_text != "" && alt_text.length() > max_graphic_alt_text_length {
    raise GraphicAltTextTooLong(
      len=alt_text.length(),
      limit=max_graphic_alt_text_length,
    )
  }
  let (
    normalized_offset_x,
    normalized_offset_y,
    normalized_scale_x,
    normalized_scale_y,
    normalized_hyperlink,
    normalized_hyperlink_type,
  ) = normalize_picture_options(
    offset_x, offset_y, scale_x, scale_y, hyperlink, hyperlink_type,
  )
  let (anchor_row, anchor_col, cell_width_px, cell_height_px) = if auto_fit {
    self.anchor_cell_size_pixels(row, col)
  } else {
    (row, col, 0, 0)
  }
  let (img_w_px, img_h_px) = match image_dimensions_px(data, ext.to_lower()) {
    Some((w, h)) => (w, h)
    None => (default_picture_width_px, default_picture_height_px)
  }
  let mut base_w_px = Double::from_int(img_w_px)
  let mut base_h_px = Double::from_int(img_h_px)
  if auto_fit {
    let cw = Double::from_int(cell_width_px)
    let ch = Double::from_int(cell_height_px)
    if auto_fit_ignore_aspect {
      base_w_px = cw
      base_h_px = ch
    } else if cw < base_w_px || ch < base_h_px {
      let asp_w = cw / base_w_px
      let asp_h = ch / base_h_px
      let asp = if asp_w < asp_h { asp_w } else { asp_h }
      base_w_px = base_w_px * asp
      base_h_px = base_h_px * asp
    }
  }
  // Validate the floating-point result before narrowing to Int. `Double::to_int`
  // saturates non-finite/out-of-range values, which would otherwise turn an
  // invalid public option into a plausible but corrupted drawing extent.
  let width_emu = drawing_scaled_extent_for_write(
    base_w_px, normalized_scale_x, "drawing image width",
  )
  let height_emu = drawing_scaled_extent_for_write(
    base_h_px, normalized_scale_y, "drawing image height",
  )
  let stored_reference = if auto_fit {
    cell_ref_from(anchor_row, anchor_col)
  } else {
    reference
  }
  let drawing_order = self.allocate_drawing_order()
  self.images.push({
    reference: stored_reference,
    data,
    extension: ext,
    content_type,
    offset_x: normalized_offset_x,
    offset_y: normalized_offset_y,
    scale_x: normalized_scale_x,
    scale_y: normalized_scale_y,
    width_emu,
    height_emu,
    print_object,
    locked,
    hyperlink: normalized_hyperlink,
    hyperlink_type: normalized_hyperlink_type,
    name,
    alt_text,
    lock_aspect_ratio,
    positioning,
    drawing_offset_x_emu: None,
    drawing_offset_y_emu: None,
    drawing_width_emu: None,
    drawing_height_emu: None,
    drawing_order: Some(drawing_order),
  })
}

///|
fn image_with_reference(image : Image, reference : String) -> Image {
  {
    reference,
    data: image.data,
    extension: image.extension,
    content_type: image.content_type,
    offset_x: image.offset_x,
    offset_y: image.offset_y,
    scale_x: image.scale_x,
    scale_y: image.scale_y,
    width_emu: image.width_emu,
    height_emu: image.height_emu,
    print_object: image.print_object,
    locked: image.locked,
    hyperlink: image.hyperlink,
    hyperlink_type: image.hyperlink_type,
    name: image.name,
    alt_text: image.alt_text,
    lock_aspect_ratio: image.lock_aspect_ratio,
    positioning: image.positioning,
    drawing_offset_x_emu: image.drawing_offset_x_emu,
    drawing_offset_y_emu: image.drawing_offset_y_emu,
    drawing_width_emu: image.drawing_width_emu,
    drawing_height_emu: image.drawing_height_emu,
    drawing_order: image.drawing_order,
  }
}

///|
fn chart_with_reference(chart : Chart, reference : String) -> Chart {
  {
    reference,
    xml: chart.xml,
    offset_x: chart.offset_x,
    offset_y: chart.offset_y,
    width_emu: chart.width_emu,
    height_emu: chart.height_emu,
    print_object: chart.print_object,
    locked: chart.locked,
    positioning: chart.positioning,
    drawing_offset_x_emu: chart.drawing_offset_x_emu,
    drawing_offset_y_emu: chart.drawing_offset_y_emu,
    drawing_width_emu: chart.drawing_width_emu,
    drawing_height_emu: chart.drawing_height_emu,
    drawing_order: chart.drawing_order,
    drawing_frame_canonical: chart.drawing_frame_canonical,
  }
}

///|
fn Worksheet::get_pictures(
  self : Worksheet,
  cell : StringView,
) -> Array[Image] raise XlsxError {
  let (row, col) = cell_ref_to_rc(cell)
  let images : Array[Image] = []
  for image in self.images {
    let (img_row, img_col) = cell_ref_to_rc(image.reference)
    if img_row == row && img_col == col {
      images.push(image)
    }
  }
  images
}

///|
fn Worksheet::get_picture_cells(
  self : Worksheet,
) -> Array[String] raise XlsxError {
  let cells : Array[String] = []
  let seen : Map[String, Bool] = Map([])
  for image in self.images {
    let (row, col) = cell_ref_to_rc(image.reference)
    let reference = cell_ref_from(row, col)
    if !seen.contains(reference) {
      seen[reference] = true
      cells.push(reference)
    }
  }
  cells
}

///|
fn Worksheet::delete_picture(
  self : Worksheet,
  cell : StringView,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let (row, col) = cell_ref_to_rc(cell)
  let updated : Array[Image] = []
  for image in self.images {
    let (img_row, img_col) = cell_ref_to_rc(image.reference)
    if img_row == row && img_col == col {
      continue
    }
    updated.push(image)
  }
  self.images.clear()
  self.images.append(updated)
}

///|
pub fn Worksheet::add_chart(
  self : Worksheet,
  reference : String,
  xml : String,
) -> Unit raise XlsxError {
  let (_row, _col) = cell_ref_to_rc(reference)
  let drawing_order = self.allocate_drawing_order()
  self.charts.push({
    reference,
    xml,
    offset_x: 0,
    offset_y: 0,
    width_emu: picture_emu_per_pixel * 480,
    height_emu: picture_emu_per_pixel * 260,
    print_object: true,
    locked: true,
    positioning: TwoCell,
    drawing_offset_x_emu: None,
    drawing_offset_y_emu: None,
    drawing_width_emu: None,
    drawing_height_emu: None,
    drawing_order: Some(drawing_order),
    drawing_frame_canonical: true,
  })
}

///|
pub fn Worksheet::add_chart_with_options(
  self : Worksheet,
  reference : String,
  opts : ChartOptions,
) -> Unit raise XlsxError {
  let (_row, _col) = cell_ref_to_rc(reference)
  let offset_x = match opts.format.offset_x {
    Some(value) => value
    None => 0
  }
  let offset_y = match opts.format.offset_y {
    Some(value) => value
    None => 0
  }
  let scale_x = match opts.format.scale_x {
    Some(value) => value
    None => 1.0
  }
  let scale_y = match opts.format.scale_y {
    Some(value) => value
    None => 1.0
  }
  if offset_x < 0 || offset_y < 0 {
    raise InvalidSheetOperation(msg="chart offset must be >= 0")
  }
  if scale_x <= 0.0 || scale_y <= 0.0 {
    raise InvalidSheetOperation(msg="chart scale must be > 0")
  }
  let print_object = match opts.format.print_object {
    Some(value) => value
    None => true
  }
  let locked = match opts.format.locked {
    Some(value) => value
    None => true
  }
  let positioning = match opts.format.positioning {
    Some(value) => value
    None => TwoCell
  }
  // Convert the pixel dimension before multiplying. Multiplying as Int first
  // can wrap on both native and Wasm before any later range check sees it.
  let width_emu = drawing_scaled_extent_for_write(
    Double::from_int(opts.dimension.width),
    scale_x,
    "drawing chart width",
  )
  let height_emu = drawing_scaled_extent_for_write(
    Double::from_int(opts.dimension.height),
    scale_y,
    "drawing chart height",
  )
  let xml = chart_options_to_xml(opts)
  let drawing_order = self.allocate_drawing_order()
  self.charts.push({
    reference,
    xml,
    offset_x,
    offset_y,
    width_emu,
    height_emu,
    print_object,
    locked,
    positioning,
    drawing_offset_x_emu: None,
    drawing_offset_y_emu: None,
    drawing_width_emu: None,
    drawing_height_emu: None,
    drawing_order: Some(drawing_order),
    drawing_frame_canonical: true,
  })
}

///|
pub fn Worksheet::delete_chart(
  self : Worksheet,
  cell : StringView,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let (row, col) = cell_ref_to_rc(cell)
  let updated : Array[Chart] = []
  for chart in self.charts {
    let (chart_row, chart_col) = cell_ref_to_rc(chart.reference)
    if chart_row == row && chart_col == col {
      continue
    }
    updated.push(chart)
  }
  self.charts.clear()
  self.charts.append(updated)
}

///|
pub fn Worksheet::add_shape(
  self : Worksheet,
  shape : Shape,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let drawing_order = self.allocate_drawing_order()
  self.shapes.push({ ..shape, drawing_order: Some(drawing_order) })
}

///|
pub fn Worksheet::add_vml_drawing_xml(
  self : Worksheet,
  xml : String,
) -> Unit raise XlsxError {
  if xml == "" {
    raise InvalidVmlDrawing(msg="vml drawing xml empty")
  }
  self.vml_drawing_xml = Some(xml)
}

///|
pub fn Worksheet::add_vml_drawing_hf_xml(
  self : Worksheet,
  xml : String,
) -> Unit raise XlsxError {
  if xml == "" {
    raise InvalidVmlDrawing(msg="vml drawing hf xml empty")
  }
  self.vml_drawing_hf_xml = Some(xml)
}

///|
pub fn Worksheet::add_form_control(
  self : Worksheet,
  control : FormControl,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  self.form_controls.push(control)
}

///|
fn Worksheet::get_form_controls(self : Worksheet) -> ArrayView[FormControl] {
  self.form_controls
}

///|
fn Worksheet::delete_form_control(
  self : Worksheet,
  cell : StringView,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let (target_row, target_col) = cell_ref_to_rc(cell)
  let remaining : Array[FormControl] = []
  let mut removed = false
  for control in self.form_controls {
    let (row, col) = cell_ref_to_rc(control.cell)
    if row == target_row && col == target_col {
      removed = true
    } else {
      remaining.push(control)
    }
  }
  if !removed {
    return
  }
  self.form_controls.clear()
  for control in remaining {
    self.form_controls.push(control)
  }
}

///|
pub fn Worksheet::add_slicer(
  self : Worksheet,
  slicer : Slicer,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let drawing_order = self.allocate_drawing_order()
  self.slicers.push({ ..slicer, drawing_order: Some(drawing_order) })
}

///|
fn Worksheet::get_slicers(self : Worksheet) -> ArrayView[Slicer] {
  self.slicers
}

///|
fn Worksheet::delete_slicer(
  self : Worksheet,
  name : StringView,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let target = name.to_owned()
  if target == "" {
    raise InvalidSheetOperation(msg="slicer name empty")
  }
  let remaining : Array[Slicer] = []
  let mut removed = false
  for slicer in self.slicers {
    if slicer.name == target {
      removed = true
    } else {
      remaining.push(slicer)
    }
  }
  if !removed {
    raise InvalidSheetOperation(msg="slicer not found")
  }
  self.slicers.clear()
  for slicer in remaining {
    self.slicers.push(slicer)
  }
}

///|
fn Worksheet::add_data_validation_xml(self : Worksheet, xml : String) -> Unit {
  self.data_validations.push(xml)
}

///|
pub fn Worksheet::add_data_validation(
  self : Worksheet,
  dv : DataValidation,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let xml = data_validation_xml(dv)
  self.data_validations.push(xml)
}

///|
pub fn Worksheet::add_data_validation_list(
  self : Worksheet,
  range_ref : String,
  values : ArrayView[String],
  allow_blank? : Bool = true,
) -> Unit raise XlsxError {
  if values.length() == 0 {
    raise UnsupportedFeature(msg="empty validation list")
  }
  let dv = DataValidation::new(allow_blank)
  dv.set_sqref(range_ref)
  dv.set_drop_list(values)
  self.add_data_validation(dv)
}

///|
pub fn Worksheet::get_data_validations(
  self : Worksheet,
) -> Array[DataValidation] raise XlsxError {
  let validations : Array[DataValidation] = []
  for xml in self.data_validations {
    validations.push(data_validation_from_xml(xml))
  }
  validations
}

///|
pub fn Worksheet::delete_data_validation(
  self : Worksheet,
  sqrefs? : Array[String] = [],
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if sqrefs.length() == 0 {
    self.data_validations.clear()
    return
  }
  let sqref_text = sqrefs.join(" ")
  let del_cells = flat_sqref(sqref_text)
  let updated : Array[String] = []
  for xml in self.data_validations {
    let tag = match tag_attributes_in(xml, "dataValidation") {
      Some(value) => value
      None => raise InvalidXml(msg="data validation tag missing")
    }
    let sqref = match attr_value(tag, "sqref") {
      Some(value) => unescape_xml_text(value)
      None => raise InvalidXml(msg="data validation sqref missing")
    }
    let next_sqref = delete_cells_from_sqref(sqref, del_cells)
    if next_sqref == "" {
      continue
    }
    match replace_attr_value_in_open_tag(xml, "sqref", next_sqref) {
      Some(value) => updated.push(value)
      None => raise InvalidXml(msg="data validation sqref update failed")
    }
  }
  self.data_validations.clear()
  self.data_validations.append(updated)
}

///|
pub fn Worksheet::add_ignored_errors(
  self : Worksheet,
  range_ref : String,
  error_type : IgnoredErrorType,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if range_ref == "" {
    raise InvalidSheetOperation(msg="ignored errors range empty")
  }
  let sqref = normalize_cell_or_range_ref(range_ref)
  let entry = ignored_error_from_type(sqref, error_type)
  for existing in self.ignored_errors {
    if existing == entry {
      return
    }
  }
  self.ignored_errors.push(entry)
}

///|
pub fn Worksheet::add_conditional_format_xml(
  self : Worksheet,
  xml : String,
) -> Unit {
  self.conditional_formats.push(xml)
}

///|
let ext_uri_conditional_formatting_rule_id = "{B025F937-C7B1-47D3-B67F-A62EFF666E3E}"

///|
let ns_spreadsheet_x14 = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"

///|
fn pad_left_dec(value : Int, width : Int) -> String {
  let text = value.to_string()
  if text.length() >= width {
    return text
  }
  let padding = width - text.length()
  String::repeat("0", padding) + text
}

///|
fn Worksheet::next_x14_cf_rule_id(self : Worksheet) -> String {
  let mut counter = self.x14_cf_rule_id_counter
  while true {
    let suffix = pad_left_dec(counter, 12)
    let id = "{00000000-0000-0000-0000-\{suffix}}"
    counter = counter + 1
    if self.x14_data_bars.get(id) is None {
      self.x14_cf_rule_id_counter = counter
      return id
    }
  }
  "{00000000-0000-0000-0000-000000000000}"
}

///|
fn next_available_x14_cf_rule_id(
  start : Int,
  used : Map[String, X14DataBarProps],
) -> (String, Int) {
  let mut counter = start
  while true {
    let suffix = pad_left_dec(counter, 12)
    let id = "{00000000-0000-0000-0000-\{suffix}}"
    counter += 1
    if used.get(id) is None {
      return (id, counter)
    }
  }
  ("{00000000-0000-0000-0000-000000000000}", counter)
}

///|
fn inject_x14_id_ext_lst_into_cf_rule(
  rule_xml : String,
  id : StringView,
) -> String raise XlsxError {
  if rule_xml.contains("") {
    return rule_xml
  }
  let close_tag = ""
  let parts = Array::from_iter(rule_xml.split(close_tag))
  if parts.length() <= 1 {
    raise InvalidXml(msg="cfRule tag invalid")
  }
  let before = parts[0].to_owned()
  let tail : Array[String] = []
  for i, part in parts {
    if i > 0 {
      tail.push(part.to_owned())
    }
  }
  let after = close_tag + tail.join(close_tag)
  "\{before}\{escape_xml_text(id)}\{after}"
}

///|
pub fn Worksheet::set_conditional_format(
  self : Worksheet,
  range_ref : String,
  options : ArrayView[ConditionalFormatOptions],
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if options.length() == 0 {
    raise InvalidConditionalFormat(msg="options empty")
  }
  let (sqref, master_cell) = prepare_conditional_format_range(range_ref)
  let mut priority = 0
  for xml in self.conditional_formats {
    let mut count = 0
    let mut first = true
    for _ in xml.split(" Map[String, Array[ConditionalFormatOptions]] raise XlsxError {
  let formats : Map[String, Array[ConditionalFormatOptions]] = Map([])
  for xml in self.conditional_formats {
    let (sqref, opts) = parse_conditional_format_xml(xml, self.x14_data_bars)
    match formats.get(sqref) {
      Some(existing) => {
        existing.append(opts)
        formats[sqref] = existing
      }
      None => formats[sqref] = opts
    }
  }
  formats
}

///|
/// Counts normalized `sqref` ranges directly from retained conditional-format
/// fragments. Unlike `get_conditional_formats`, this does not materialize rule
/// objects, maps, or copied range strings. Both retained-source work and the
/// result are bounded, and long scans poll `cancelled`.
pub fn conditional_format_xml_range_count_limited(
  xml : StringView,
  maximum_ranges : Int,
  maximum_work_units : Int,
  cancelled? : () -> Bool = () => false,
) -> Int raise XlsxError {
  if maximum_ranges < 0 || maximum_work_units < 0 {
    raise InvalidOptions(
      msg="conditional-format count limits must be non-negative",
    )
  }
  let (work, work_exceeded) = read_budget_actual(
    0,
    xml.length(),
    maximum_work_units,
  )
  if work_exceeded {
    raise ResourceLimitExceeded(
      kind="conditional_format_count_work_units",
      limit=maximum_work_units,
      actual=work,
    )
  }
  check_read_cancelled(cancelled)
  let scanner = @ooxml.XmlStartTagScanner::new(xml, cancelled~)
  if !workbook_scanner_next(scanner) ||
    scanner.depth() != 1 ||
    scanner.local_name() != "conditionalFormatting" {
    raise InvalidXml(msg="conditionalFormatting tag missing")
  }
  let sqref = scanner.attribute_view("", "sqref") catch {
    InvalidXml(msg~) => raise InvalidXml(msg~)
    ReadCancelled => raise ReadCancelled
  }
  guard sqref is Some(sqref) else {
    raise InvalidXml(msg="conditional formatting sqref missing")
  }
  let mut count = 0
  let mut in_token = false
  for index in 0.. Bool = () => false,
) -> Int raise XlsxError {
  if maximum_ranges < 0 || maximum_work_units < 0 {
    raise InvalidOptions(
      msg="conditional-format count limits must be non-negative",
    )
  }
  let mut count = 0
  let mut work = 0
  for xml in self.conditional_formats {
    check_read_cancelled(cancelled)
    let (next_work, work_exceeded) = read_budget_actual(
      work,
      xml.length(),
      maximum_work_units,
    )
    if work_exceeded {
      raise ResourceLimitExceeded(
        kind="conditional_format_count_work_units",
        limit=maximum_work_units,
        actual=next_work,
      )
    }
    work = next_work
    let fragment_count = conditional_format_xml_range_count_limited(
      xml,
      maximum_ranges,
      xml.length(),
      cancelled~,
    )
    let (next_count, count_exceeded) = read_budget_actual(
      count, fragment_count, maximum_ranges,
    )
    if count_exceeded {
      raise ResourceLimitExceeded(
        kind="conditional_format_ranges",
        limit=maximum_ranges,
        actual=next_count,
      )
    }
    count = next_count
  }
  check_read_cancelled(cancelled)
  count
}

///|
test "conditional-format range count stays allocation-free and bounded" {
  let sheet = Worksheet::new("Sheet1")
  sheet.conditional_formats.push(
    (
      #|
    ),
  )
  sheet.conditional_formats.push(
    (
      #|
    ),
  )
  inspect(sheet.conditional_format_range_count_limited(3, 4096), content="3")
  try sheet.conditional_format_range_count_limited(2, 4096) catch {
    ResourceLimitExceeded(kind~, limit~, actual~) => {
      inspect(kind, content="conditional_format_ranges")
      assert_eq(limit, 2)
      assert_eq(actual, 3)
    }
    _ => fail("expected conditional-format range limit")
  } noraise {
    _ => fail("expected conditional-format range limit")
  }
}

///|
test "conditional-format range count polls cancellation" {
  let sheet = Worksheet::new("Sheet1")
  sheet.conditional_formats.push(
    "",
  )
  let checks = [0]
  try
    sheet.conditional_format_range_count_limited(5000, 64 * 1024, cancelled=() => {
      checks[0] += 1
      checks[0] >= 3
    })
  catch {
    ReadCancelled => assert_true(checks[0] >= 3)
    _ => fail("expected conditional-format count cancellation")
  } noraise {
    _ => fail("expected conditional-format count cancellation")
  }
}

///|
pub fn Worksheet::unset_conditional_format(
  self : Worksheet,
  range_ref : String,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  let del_cells = flat_sqref(
    range_ref.to_string().replace_all(old=",", new=" "),
  )
  let updated : Array[(String, String)] = []
  for xml in self.conditional_formats {
    let tag = match tag_attributes_in(xml, "conditionalFormatting") {
      Some(value) => value
      None => raise InvalidXml(msg="conditionalFormatting tag missing")
    }
    let sqref = match attr_value(tag, "sqref") {
      Some(value) => unescape_xml_text(value)
      None => raise InvalidXml(msg="conditionalFormatting sqref missing")
    }
    let next_sqref = delete_cells_from_sqref(sqref, del_cells)
    if next_sqref == "" {
      continue
    }
    match replace_attr_value_in_open_tag(xml, "sqref", next_sqref) {
      Some(value) => updated.push((value, next_sqref))
      None => raise InvalidXml(msg="conditionalFormatting sqref update failed")
    }
  }
  self.conditional_formats.clear()
  for item in updated {
    let (xml, _sqref) = item
    self.conditional_formats.push(xml)
  }
  if self.x14_data_bars.length() > 0 {
    let prior : Map[String, X14DataBarProps] = Map([])
    for id, props in self.x14_data_bars {
      prior[id] = props
    }
    let referenced : Map[String, X14DataBarProps] = Map([])
    for item in updated {
      let (xml, sqref) = item
      let mut first = true
      for chunk in xml.split("") {
        if first {
          first = false
          continue
        }
        let text = chunk.to_owned()
        let end = match text.find("") {
          Some(pos) => pos
          None => continue
        }
        let id = unescape_xml_text(text[:end])
        match prior.get(id) {
          Some(props) =>
            referenced[id] = {
              sqref,
              bar_direction: props.bar_direction,
              bar_solid: props.bar_solid,
              bar_border_color: props.bar_border_color,
            }
          None => ()
        }
      }
    }
    self.x14_data_bars.clear()
    for id, props in referenced {
      self.x14_data_bars[id] = props
    }
  }
}

///|
pub fn Worksheet::set_cell_rc(
  self : Worksheet,
  row : Int,
  col : Int,
  value : String,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  self.invalidate_shared_formula_masters_index()
  let reference = cell_ref_from(row, col)
  match self.cell_index_of(row, col) {
    Some(i) => {
      let style_id = self.cells[i].style_id
      self.cells[i] = {
        reference,
        row,
        col,
        value,
        value_type: String,
        rich_text: None,
        formula: None,
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: false,
        style_explicit: self.cells[i].style_explicit,
        style_id,
      }
    }
    None => {
      let index = self.cells.length()
      self.cells.push({
        reference,
        row,
        col,
        value,
        value_type: String,
        rich_text: None,
        formula: None,
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: false,
        style_explicit: false,
        style_id: 0,
      })
      self.record_cell_index_if_valid(row, col, index)
    }
  }
}

///|
pub fn Worksheet::set_cell_value_rc(
  self : Worksheet,
  row : Int,
  col : Int,
  value : CellValue,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  self.invalidate_shared_formula_masters_index()
  let reference = cell_ref_from(row, col)
  let value_type = cell_value_type(value)
  let raw_value = cell_value_raw_string(value)
  match self.cell_index_of(row, col) {
    Some(i) => {
      let style_id = self.cells[i].style_id
      self.cells[i] = {
        reference,
        row,
        col,
        value: raw_value,
        value_type,
        rich_text: None,
        formula: None,
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: false,
        style_explicit: self.cells[i].style_explicit,
        style_id,
      }
    }
    None => {
      let index = self.cells.length()
      self.cells.push({
        reference,
        row,
        col,
        value: raw_value,
        value_type,
        rich_text: None,
        formula: None,
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: false,
        style_explicit: false,
        style_id: 0,
      })
      self.record_cell_index_if_valid(row, col, index)
    }
  }
}

///|
pub fn Worksheet::set_cell_formula_rc(
  self : Worksheet,
  row : Int,
  col : Int,
  formula : String,
  value? : String = "",
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  self.invalidate_shared_formula_masters_index()
  let reference = cell_ref_from(row, col)
  match self.cell_index_of(row, col) {
    Some(i) => {
      let style_id = self.cells[i].style_id
      self.cells[i] = {
        reference,
        row,
        col,
        value,
        value_type: String,
        rich_text: None,
        formula: Some(formula),
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: value != "",
        style_explicit: self.cells[i].style_explicit,
        style_id,
      }
    }
    None => {
      let index = self.cells.length()
      self.cells.push({
        reference,
        row,
        col,
        value,
        value_type: String,
        rich_text: None,
        formula: Some(formula),
        formula_type: None,
        formula_ref: None,
        formula_shared_index: None,
        formula_value_present: value != "",
        style_explicit: false,
        style_id: 0,
      })
      self.record_cell_index_if_valid(row, col, index)
    }
  }
}

///|
pub fn Worksheet::get_cell_rc(
  self : Worksheet,
  row : Int,
  col : Int,
) -> String? raise XlsxError {
  if row <= 0 || col <= 0 {
    raise InvalidCellRef(value="\{col}:\{row}")
  }
  match self.cell_index_of(row, col) {
    Some(i) => Some(self.cells[i].value)
    None => None
  }
}

///|
fn Worksheet::get_cell_value_raw_rc(
  self : Worksheet,
  row : Int,
  col : Int,
) -> CellValue? raise XlsxError {
  if row <= 0 || col <= 0 {
    raise InvalidCellRef(value="\{col}:\{row}")
  }
  match self.cell_index_of(row, col) {
    Some(i) =>
      Some(cell_value_from_raw(self.cells[i].value_type, self.cells[i].value))
    None => None
  }
}

///|
pub fn Worksheet::max_row(self : Worksheet) -> Int {
  let mut max_row = 0
  for cell in self.cells {
    if cell.row > max_row {
      max_row = cell.row
    }
  }
  max_row
}

///|
pub fn Worksheet::max_col(self : Worksheet) -> Int {
  let mut max_col = 0
  for cell in self.cells {
    if cell.col > max_col {
      max_col = cell.col
    }
  }
  max_col
}

///|
/// Returns the number of stored cell records in this worksheet in O(1) time.
/// This is a representation count, not the area of the logical used range;
/// callers can use it to preflight aggregate scan work before iteration.
pub fn Worksheet::stored_cell_count(self : Worksheet) -> Int {
  self.cells.length()
}

///|
/// Returns the used `(max_row, max_column)` bounds after rejecting a worksheet
/// whose stored-cell representation exceeds `maximum_stored_cells`. The O(1)
/// length preflight happens before the scan, so duplicate coordinates cannot
/// hide unbounded preprocessing behind a tiny logical used range.
pub fn Worksheet::used_bounds_limited(
  self : Worksheet,
  maximum_stored_cells~ : Int,
  cancelled? : () -> Bool = () => false,
) -> (Int, Int) raise XlsxError {
  if maximum_stored_cells < 1 {
    raise InvalidOptions(msg="maximum stored cells must be positive")
  }
  let stored = self.stored_cell_count()
  if stored > maximum_stored_cells {
    raise ResourceLimitExceeded(
      kind="stored_cells",
      limit=maximum_stored_cells,
      actual=stored,
    )
  }
  let mut max_row = 0
  let mut max_col = 0
  for index, cell in self.cells {
    if (index & 4095) == 0 && cancelled() {
      raise ReadCancelled
    }
    if cell.row > max_row {
      max_row = cell.row
    }
    if cell.col > max_col {
      max_col = cell.col
    }
  }
  if cancelled() {
    raise ReadCancelled
  }
  (max_row, max_col)
}

///|
/// Writes `values` across row `row` (1-based) starting at column A, one raw
/// string per cell. Cells beyond `values` are left unchanged. For a single
/// typed cell use `set_cell_value`; to build very large sheets efficiently use
/// the stream writer (`Workbook::new_stream_writer`).
///
/// Raises `XlsxError` if `row` is less than 1, or — when `values` is non-empty
/// — `StreamModeConflict` if the worksheet is driven by a stream writer.
pub fn Worksheet::set_row(
  self : Worksheet,
  row : Int,
  values : ArrayView[String],
) -> Unit raise XlsxError {
  // Preflight the whole write so it is all-or-nothing: writing incrementally
  // and only discovering an out-of-grid coordinate partway (row past the grid,
  // or more values than columns) would leave the row half-populated.
  if row <= 0 || row > cell_ref_max_rows {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  if values.length() > cell_ref_max_cols {
    raise InvalidCellRef(value="\{values.length()}:\{row}")
  }
  for i, value in values {
    self.set_cell_rc(row, i + 1, value)
  }
}

///|
/// Returns the raw string values of row `row` (1-based) from column A through
/// the last populated cell. Empty cells within that span are returned as empty
/// strings. Returns an empty array for a row with no cells.
///
/// Raises `XlsxError` if `row` is less than 1.
pub fn Worksheet::get_row(
  self : Worksheet,
  row : Int,
) -> Array[String] raise XlsxError {
  if row <= 0 {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  let mut max_col = 0
  for cell in self.cells {
    if cell.row == row && cell.col > max_col {
      max_col = cell.col
    }
  }
  if max_col == 0 {
    return []
  }
  let values : Array[String] = Array::make(max_col, "")
  for cell in self.cells {
    if cell.row == row {
      values[cell.col - 1] = cell.value
    }
  }
  values
}

///|
/// Writes `values` down column `col` (1-based) starting at row 1, one raw
/// string per cell. Cells beyond `values` are left unchanged.
///
/// Raises `XlsxError` if `col` is less than 1, or — when `values` is non-empty
/// — `StreamModeConflict` if the worksheet is driven by a stream writer.
pub fn Worksheet::set_col(
  self : Worksheet,
  col : Int,
  values : ArrayView[String],
) -> Unit raise XlsxError {
  // Preflight (see set_row): all-or-nothing, never a half-written column.
  if col <= 0 || col > cell_ref_max_cols {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  if values.length() > cell_ref_max_rows {
    raise InvalidCellRef(value="\{col}:\{values.length()}")
  }
  for i, value in values {
    self.set_cell_rc(i + 1, col, value)
  }
}

///|
pub fn Worksheet::get_col(
  self : Worksheet,
  col : Int,
) -> Array[String] raise XlsxError {
  if col <= 0 {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  let mut max_row = 0
  for cell in self.cells {
    if cell.col == col && cell.row > max_row {
      max_row = cell.row
    }
  }
  if max_row == 0 {
    return []
  }
  let values : Array[String] = Array::make(max_row, "")
  for cell in self.cells {
    if cell.col == col {
      values[cell.row - 1] = cell.value
    }
  }
  values
}

///|
fn default_row_dimension() -> RowDimension {
  { height: None, hidden: false, outline_level: 0, style_id: None }
}

///|
fn default_col_dimension() -> ColDimension {
  { width: None, hidden: false, outline_level: 0, style_id: None }
}

///|
fn row_dimension_is_default(dim : RowDimension) -> Bool {
  dim.height is None &&
  dim.hidden == false &&
  dim.outline_level == 0 &&
  dim.style_id is None
}

///|
fn col_dimension_is_default(dim : ColDimension) -> Bool {
  dim.width is None &&
  dim.hidden == false &&
  dim.outline_level == 0 &&
  dim.style_id is None
}

///|
fn Worksheet::row_dimension_value(self : Worksheet, row : Int) -> RowDimension {
  match self.row_dimensions.get(row) {
    Some(value) => value
    None => default_row_dimension()
  }
}

///|
fn Worksheet::col_dimension_value(self : Worksheet, col : Int) -> ColDimension {
  match self.col_dimensions.get(col) {
    Some(value) => value
    None => default_col_dimension()
  }
}

///|
fn Worksheet::set_row_dimension(
  self : Worksheet,
  row : Int,
  dim : RowDimension,
) -> Unit raise XlsxError {
  // The single choke point for every row-dimension write (heights, visibility,
  // outline levels, styles, and the stream writer): reject an out-of-grid key so
  // no `` beyond the sheet's rows is ever stored or serialized.
  if row < 1 || row > cell_ref_max_rows {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  if row_dimension_is_default(dim) {
    self.row_dimensions.remove(row)
  } else {
    self.row_dimensions[row] = dim
  }
}

///|
fn Worksheet::set_col_dimension(
  self : Worksheet,
  col : Int,
  dim : ColDimension,
) -> Unit raise XlsxError {
  if col < 1 || col > cell_ref_max_cols {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  if col_dimension_is_default(dim) {
    self.col_dimensions.remove(col)
  } else {
    self.col_dimensions[col] = dim
  }
}

///|
pub fn Worksheet::set_row_height(
  self : Worksheet,
  row : Int,
  height : Double,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if row <= 0 {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  if height < 0.0 {
    raise InvalidSheetOperation(msg="row height is negative")
  }
  let dim = self.row_dimension_value(row)
  let updated : RowDimension = {
    height: Some(height),
    hidden: dim.hidden,
    outline_level: dim.outline_level,
    style_id: dim.style_id,
  }
  self.set_row_dimension(row, updated)
}

///|
pub fn Worksheet::get_row_height(
  self : Worksheet,
  row : Int,
) -> Double? raise XlsxError {
  if row <= 0 {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  match self.row_dimensions.get(row) {
    Some(dim) => dim.height
    None => None
  }
}

///|
pub fn Worksheet::set_row_visible(
  self : Worksheet,
  row : Int,
  visible : Bool,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if row <= 0 {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  let dim = self.row_dimension_value(row)
  let updated : RowDimension = {
    height: dim.height,
    hidden: !visible,
    outline_level: dim.outline_level,
    style_id: dim.style_id,
  }
  self.set_row_dimension(row, updated)
}

///|
pub fn Worksheet::row_visible(
  self : Worksheet,
  row : Int,
) -> Bool raise XlsxError {
  if row <= 0 {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  match self.row_dimensions.get(row) {
    Some(dim) => !dim.hidden
    None => true
  }
}

///|
pub fn Worksheet::set_row_outline_level(
  self : Worksheet,
  row : Int,
  level : Int,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if row <= 0 {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  if level < 0 || level > 7 {
    raise InvalidSheetOperation(msg="row outline level out of range")
  }
  let dim = self.row_dimension_value(row)
  let updated : RowDimension = {
    height: dim.height,
    hidden: dim.hidden,
    outline_level: level,
    style_id: dim.style_id,
  }
  self.set_row_dimension(row, updated)
}

///|
fn Worksheet::row_outline_level(
  self : Worksheet,
  row : Int,
) -> Int raise XlsxError {
  if row <= 0 {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  match self.row_dimensions.get(row) {
    Some(dim) => dim.outline_level
    None => 0
  }
}

///|
fn Worksheet::set_row_style_range(
  self : Worksheet,
  start : Int,
  end : Int,
  style_id : Int,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if start <= 0 || end <= 0 {
    raise InvalidCellRef(value="\{0}:\{start}")
  }
  if end < start {
    raise InvalidSheetOperation(msg="row style range invalid")
  }
  // Preflight the upper bound so the range write is all-or-nothing.
  if end > cell_ref_max_rows {
    raise InvalidCellRef(value="\{0}:\{end}")
  }
  let style = if style_id > 0 { Some(style_id) } else { None }
  for row in start..<=end {
    let dim = self.row_dimension_value(row)
    let updated : RowDimension = {
      height: dim.height,
      hidden: dim.hidden,
      outline_level: dim.outline_level,
      style_id: style,
    }
    self.set_row_dimension(row, updated)
  }
}

///|
pub fn Worksheet::set_row_style(
  self : Worksheet,
  row : Int,
  style_id : Int,
) -> Unit raise XlsxError {
  self.set_row_style_range(row, row, style_id)
}

///|
fn Worksheet::get_row_style(
  self : Worksheet,
  row : Int,
) -> Int? raise XlsxError {
  if row <= 0 {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  match self.row_dimensions.get(row) {
    Some(dim) => dim.style_id
    None => None
  }
}

///|
pub fn Worksheet::set_col_width(
  self : Worksheet,
  col : Int,
  width : Double,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if col <= 0 {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  if width < 0.0 {
    raise InvalidSheetOperation(msg="column width is negative")
  }
  let dim = self.col_dimension_value(col)
  let updated : ColDimension = {
    width: Some(width),
    hidden: dim.hidden,
    outline_level: dim.outline_level,
    style_id: dim.style_id,
  }
  self.set_col_dimension(col, updated)
}

///|
pub fn Worksheet::get_col_width(
  self : Worksheet,
  col : Int,
) -> Double? raise XlsxError {
  if col <= 0 {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  match self.col_dimensions.get(col) {
    Some(dim) => dim.width
    None => None
  }
}

///|
pub fn Worksheet::set_col_visible(
  self : Worksheet,
  col : Int,
  visible : Bool,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if col <= 0 {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  let dim = self.col_dimension_value(col)
  let updated : ColDimension = {
    width: dim.width,
    hidden: !visible,
    outline_level: dim.outline_level,
    style_id: dim.style_id,
  }
  self.set_col_dimension(col, updated)
}

///|
pub fn Worksheet::col_visible(
  self : Worksheet,
  col : Int,
) -> Bool raise XlsxError {
  if col <= 0 {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  match self.col_dimensions.get(col) {
    Some(dim) => !dim.hidden
    None => true
  }
}

///|
fn Worksheet::set_col_outline_level(
  self : Worksheet,
  col : Int,
  level : Int,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if col <= 0 {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  if level < 0 || level > 7 {
    raise InvalidSheetOperation(msg="column outline level out of range")
  }
  let dim = self.col_dimension_value(col)
  let updated : ColDimension = {
    width: dim.width,
    hidden: dim.hidden,
    outline_level: level,
    style_id: dim.style_id,
  }
  self.set_col_dimension(col, updated)
}

///|
pub fn Worksheet::col_outline_level(
  self : Worksheet,
  col : Int,
) -> Int raise XlsxError {
  if col <= 0 {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  match self.col_dimensions.get(col) {
    Some(dim) => dim.outline_level
    None => 0
  }
}

///|
fn Worksheet::set_col_style(
  self : Worksheet,
  col : Int,
  style_id : Int,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if col <= 0 {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  let dim = self.col_dimension_value(col)
  let style = if style_id > 0 { Some(style_id) } else { None }
  let updated : ColDimension = {
    width: dim.width,
    hidden: dim.hidden,
    outline_level: dim.outline_level,
    style_id: style,
  }
  self.set_col_dimension(col, updated)
}

///|
pub fn Worksheet::get_col_style(
  self : Worksheet,
  col : Int,
) -> Int? raise XlsxError {
  if col <= 0 {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  match self.col_dimensions.get(col) {
    Some(dim) => dim.style_id
    None => None
  }
}

///|
fn Worksheet::insert_rows(
  self : Worksheet,
  row : Int,
  count : Int,
  formula_limits? : SharedFormulaLimits = SharedFormulaLimits::new(),
  cancelled? : () -> Bool = () => false,
  formula_budget? : SharedFormulaMaterializationBudget,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if row <= 0 || row > cell_ref_max_rows {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  if count <= 0 {
    raise InvalidSheetOperation(msg="row count must be positive")
  }
  // A count larger than the grid is meaningless and, more importantly, would let
  // `existing_row + count` wrap `Int` and slip past the upper-bound checks below.
  if count > cell_ref_max_rows {
    raise InvalidSheetOperation(
      msg="row count \{count} exceeds the sheet's \{cell_ref_max_rows} rows",
    )
  }
  let translation_budget = match formula_budget {
    Some(value) => value
    None => SharedFormulaMaterializationBudget::new(formula_limits, cancelled~)
  }
  let shared_formula_masters = validated_shared_formula_masters(
    self.cells,
    cancelled=translation_budget.cancelled,
  )
  preflight_shared_formula_materialization(
    self.cells,
    shared_formula_masters,
    translation_budget,
    fn(_cell : Cell) -> Bool { true },
  )
  translation_budget.checkpoint()
  // Transactional: stage every shifted collection into locals first — cell,
  // merge, conditional-format, validation, hyperlink, filter, table,
  // sparkline, image, and chart references shift through
  // `cell_ref_from`/range adjusters that raise once a coordinate leaves the
  // grid, and the two numerically-shifted collections (row dimensions, page
  // breaks) are bound-checked explicitly below. Nothing on `self` is mutated
  // until every stage succeeds, so an overflowing insert raises and leaves the
  // worksheet unchanged instead of half-shifted.
  let updated_cells : Array[Cell] = []
  for index, stored_cell in self.cells {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let cell = normal_formula_cell_for_structural_edit(
      stored_cell, shared_formula_masters, translation_budget,
    )
    if cell.row >= row {
      let new_row = cell.row + count
      let reference = cell_ref_from(new_row, cell.col)
      updated_cells.push({
        reference,
        row: new_row,
        col: cell.col,
        value: cell.value,
        value_type: cell.value_type,
        rich_text: cell.rich_text,
        formula: cell.formula,
        formula_type: cell.formula_type,
        formula_ref: cell.formula_ref,
        formula_shared_index: cell.formula_shared_index,
        formula_value_present: cell.formula_value_present,
        style_explicit: cell.style_explicit,
        style_id: cell.style_id,
      })
    } else {
      updated_cells.push(cell)
    }
  }
  let updated_merges : Array[String] = []
  for index, range_ref in self.merged_cells {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    updated_merges.push(adjust_range_after_row_insert(range_ref, row, count))
  }
  let updated_conditional_formats = adjust_xml_sqrefs_after_insert(
    self.conditional_formats,
    row,
    count,
    SqrefRows,
    cancelled=translation_budget.cancelled,
  )
  let updated_x14_data_bars = adjust_x14_data_bars_after_insert(
    self.x14_data_bars,
    row,
    count,
    SqrefRows,
    cancelled=translation_budget.cancelled,
  )
  let updated_data_validations = adjust_xml_sqrefs_after_insert(
    self.data_validations,
    row,
    count,
    SqrefRows,
    cancelled=translation_budget.cancelled,
  )
  let updated_links : Array[Hyperlink] = []
  for index, link in self.hyperlinks {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let reference = adjust_hyperlink_ref_after_row_insert(
      link.reference,
      row,
      count,
    )
    updated_links.push({
      reference,
      target: link.target,
      link_type: link.link_type,
      location: link.location,
      display: link.display,
      tooltip: link.tooltip,
    })
  }
  translation_budget.checkpoint()
  let updated_filter = match self.auto_filter {
    Some(filter) =>
      Some(adjust_auto_filter_after_row_insert(filter, row, count))
    None => None
  }
  let updated_tables : Array[Table] = []
  for index, table in self.tables {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    updated_tables.push(
      adjust_table_after_row_insert(
        table,
        row,
        count,
        cancelled=translation_budget.cancelled,
      ),
    )
  }
  let updated_sparklines : Array[SparklineGroup] = []
  for index, group in self.sparkline_groups {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let adjusted = adjust_sparkline_group_after_row_insert(
      group,
      row,
      count,
      cancelled=translation_budget.cancelled,
    )
    if adjusted.sparklines.length() > 0 {
      updated_sparklines.push(adjusted)
    }
  }
  let updated_images : Array[Image] = []
  for index, image in self.images {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let reference = adjust_cell_after_row_insert(image.reference, row, count)
    updated_images.push(image_with_reference(image, reference))
  }
  let updated_charts : Array[Chart] = []
  for index, chart in self.charts {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let reference = adjust_cell_after_row_insert(chart.reference, row, count)
    updated_charts.push(chart_with_reference(chart, reference))
  }
  let updated_rows : Map[Int, RowDimension] = Map([])
  let mut dimension_index = 0
  for row_index, dim in self.row_dimensions {
    if (dimension_index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let new_row = if row_index >= row {
      // Overflow-safe: a stored dimension key can be arbitrarily large (the
      // dimension setters do not bound it), so validate BEFORE the addition.
      if row_index > cell_ref_max_rows - count {
        raise InvalidCellRef(value="\{0}:\{row_index}")
      }
      row_index + count
    } else {
      row_index
    }
    updated_rows[new_row] = dim
    dimension_index += 1
  }
  let break_start = row - 1
  // Break ids are 0-based (id = row - 1), so a shifted id must stay strictly
  // below the row maximum. Check the original ids overflow-safely, before
  // adjust_page_breaks_after_insert performs `id + count`.
  for index, brk in self.row_breaks {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    if brk.id >= break_start && brk.id > cell_ref_max_rows - 1 - count {
      raise InvalidCellRef(value="\{0}:\{brk.id}")
    }
  }
  let updated_breaks = adjust_page_breaks_after_insert(
    self.row_breaks,
    break_start,
    count,
    cancelled=translation_budget.cancelled,
  )
  // Commit: every stage above succeeded, so applying the staged state cannot
  // fail partway.
  translation_budget.checkpoint()
  self.invalidate_shared_formula_masters_index()
  self.invalidate_cell_index()
  self.cells.clear()
  self.cells.append(updated_cells)
  self.merged_cells.clear()
  self.merged_cells.append(updated_merges)
  self.conditional_formats.clear()
  self.conditional_formats.append(updated_conditional_formats)
  self.x14_data_bars.clear()
  for id, props in updated_x14_data_bars {
    self.x14_data_bars[id] = props
  }
  self.data_validations.clear()
  self.data_validations.append(updated_data_validations)
  self.hyperlinks.clear()
  self.hyperlinks.append(updated_links)
  self.auto_filter = updated_filter
  self.tables.clear()
  self.tables.append(updated_tables)
  self.sparkline_groups.clear()
  self.sparkline_groups.append(updated_sparklines)
  self.images.clear()
  self.images.append(updated_images)
  self.charts.clear()
  self.charts.append(updated_charts)
  self.row_dimensions.clear()
  for row_index, dim in updated_rows {
    self.row_dimensions[row_index] = dim
  }
  self.row_breaks.clear()
  self.row_breaks.append(updated_breaks)
}

///|
fn Worksheet::remove_rows(
  self : Worksheet,
  row : Int,
  count : Int,
  formula_limits? : SharedFormulaLimits = SharedFormulaLimits::new(),
  cancelled? : () -> Bool = () => false,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if row <= 0 {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  if count <= 0 {
    raise InvalidSheetOperation(msg="row count must be positive")
  }
  // Bound both the start and the count so `row + count - 1` cannot wrap `Int`
  // (a start or count beyond the grid removes nothing meaningful anyway).
  if row > cell_ref_max_rows {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  if count > cell_ref_max_rows {
    raise InvalidSheetOperation(
      msg="row count \{count} exceeds the sheet's \{cell_ref_max_rows} rows",
    )
  }
  let translation_budget = SharedFormulaMaterializationBudget::new(
    formula_limits,
    cancelled~,
  )
  let shared_formula_masters = validated_shared_formula_masters(
    self.cells,
    cancelled=translation_budget.cancelled,
  )
  let end_row = row + count - 1
  preflight_shared_formula_materialization(
    self.cells,
    shared_formula_masters,
    translation_budget,
    fn(cell : Cell) -> Bool { cell.row < row || cell.row > end_row },
  )
  translation_budget.checkpoint()
  let updated_cells : Array[Cell] = []
  for index, stored_cell in self.cells {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    if stored_cell.row >= row && stored_cell.row <= end_row {
      continue
    }
    let cell = normal_formula_cell_for_structural_edit(
      stored_cell, shared_formula_masters, translation_budget,
    )
    if cell.row < row {
      updated_cells.push(cell)
      continue
    }
    let new_row = cell.row - count
    let reference = cell_ref_from(new_row, cell.col)
    updated_cells.push({
      reference,
      row: new_row,
      col: cell.col,
      value: cell.value,
      value_type: cell.value_type,
      rich_text: cell.rich_text,
      formula: cell.formula,
      formula_type: cell.formula_type,
      formula_ref: cell.formula_ref,
      formula_shared_index: cell.formula_shared_index,
      formula_value_present: cell.formula_value_present,
      style_explicit: cell.style_explicit,
      style_id: cell.style_id,
    })
  }
  let updated_merges : Array[String] = []
  for index, range_ref in self.merged_cells {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    match adjust_range_after_row_remove(range_ref, row, count) {
      Some(value) => updated_merges.push(value)
      None => ()
    }
  }
  let updated_links : Array[Hyperlink] = []
  for index, link in self.hyperlinks {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    match adjust_hyperlink_ref_after_row_remove(link.reference, row, count) {
      Some(reference) =>
        updated_links.push({
          reference,
          target: link.target,
          link_type: link.link_type,
          location: link.location,
          display: link.display,
          tooltip: link.tooltip,
        })
      None => ()
    }
  }
  translation_budget.checkpoint()
  let updated_filter = match self.auto_filter {
    Some(filter) =>
      match adjust_auto_filter_after_row_remove(filter, row, count) {
        Some(updated) => Some(updated)
        None => None
      }
    None => None
  }
  let updated_tables : Array[Table] = []
  for index, table in self.tables {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    match
      adjust_table_after_row_remove(
        table,
        row,
        count,
        cancelled=translation_budget.cancelled,
      ) {
      Some(value) => updated_tables.push(value)
      None => ()
    }
  }
  let updated_sparklines : Array[SparklineGroup] = []
  for index, group in self.sparkline_groups {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let adjusted = adjust_sparkline_group_after_row_remove(
      group,
      row,
      count,
      cancelled=translation_budget.cancelled,
    )
    if adjusted.sparklines.length() > 0 {
      updated_sparklines.push(adjusted)
    }
  }
  let updated_images : Array[Image] = []
  for index, image in self.images {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    match adjust_cell_after_row_remove(image.reference, row, count) {
      Some(reference) =>
        updated_images.push(image_with_reference(image, reference))
      None => ()
    }
  }
  let updated_charts : Array[Chart] = []
  for index, chart in self.charts {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    match adjust_cell_after_row_remove(chart.reference, row, count) {
      Some(reference) =>
        updated_charts.push(chart_with_reference(chart, reference))
      None => ()
    }
  }
  let updated_rows : Map[Int, RowDimension] = Map([])
  let mut dimension_index = 0
  for row_index, dim in self.row_dimensions {
    if (dimension_index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    if row_index < row {
      updated_rows[row_index] = dim
    } else if row_index > end_row {
      updated_rows[row_index - count] = dim
    }
    dimension_index += 1
  }
  let break_start = row - 1
  let updated_breaks = adjust_page_breaks_after_remove(
    self.row_breaks,
    break_start,
    count,
    cancelled=translation_budget.cancelled,
  )
  // One final cancellation point precedes the only mutation phase. No
  // cancellation callback runs after this point, so cancellation is atomic.
  translation_budget.checkpoint()
  self.invalidate_shared_formula_masters_index()
  self.invalidate_cell_index()
  self.cells.clear()
  self.cells.append(updated_cells)
  self.merged_cells.clear()
  self.merged_cells.append(updated_merges)
  self.hyperlinks.clear()
  self.hyperlinks.append(updated_links)
  self.auto_filter = updated_filter
  self.tables.clear()
  self.tables.append(updated_tables)
  self.sparkline_groups.clear()
  self.sparkline_groups.append(updated_sparklines)
  self.images.clear()
  self.images.append(updated_images)
  self.charts.clear()
  self.charts.append(updated_charts)
  self.row_dimensions.clear()
  for row_index, dim in updated_rows {
    self.row_dimensions[row_index] = dim
  }
  self.row_breaks.clear()
  self.row_breaks.append(updated_breaks)
}

///|
fn parse_cell_ref_with_abs(
  reference : StringView,
) -> (Int, Int, Bool, Bool) raise XlsxError {
  parse_cell_ref_parts(reference)
}

///|
fn format_cell_ref_with_abs(
  row : Int,
  col : Int,
  abs_col : Bool,
  abs_row : Bool,
) -> String raise XlsxError {
  let col_text = column_number_to_name(col)
  if row <= 0 || row > cell_ref_max_rows {
    raise InvalidCellRef(value="\{col}:\{row}")
  }
  let row_text = row.to_string()
  let sb = StringBuilder::new()
  if abs_col {
    sb.write_char('$')
  }
  sb.write_view(col_text)
  if abs_row {
    sb.write_char('$')
  }
  sb.write_view(row_text)
  sb.to_string()
}

///|
fn split_sqref_range(text : StringView) -> (String, String) {
  let left = StringBuilder::new()
  let right = StringBuilder::new()
  let mut seen_sep = false
  for ch in text {
    if !seen_sep && ch == ':' {
      seen_sep = true
    } else if seen_sep {
      right.write_char(ch)
    } else {
      left.write_char(ch)
    }
  }
  if seen_sep {
    (left.to_string(), right.to_string())
  } else {
    let cell = text.to_owned()
    (cell, cell)
  }
}

///|
fn decode_structural_sqref(
  encoded : StringView,
  cancelled? : () -> Bool = () => false,
) -> String raise XlsxError {
  @ooxml.decode_xml_attribute(encoded, cancelled~) catch {
    InvalidXml(msg~) => raise InvalidXml(msg~)
    ReadCancelled => raise ReadCancelled
  }
}

///|
priv enum SqrefInsertAxis {
  SqrefRows
  SqrefColumns
}

///|
fn adjust_sqref_after_insert(
  sqref : StringView,
  start : Int,
  count : Int,
  axis : SqrefInsertAxis,
  cancelled? : () -> Bool = () => false,
) -> String raise XlsxError {
  let adjusted : Array[String] = []
  let tokens = xml_whitespace_tokens_cancellable(sqref, cancelled~)
  if tokens.length() == 0 {
    raise InvalidXml(msg="sqref reference invalid")
  }
  for index, token in tokens {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    if token.length() > 128 {
      raise InvalidXml(msg="sqref reference invalid")
    }
    let had_range = token.contains(":")
    let range_ref = if had_range { token } else { token + ":" + token }
    let (min_row, min_col, max_row, max_col) = parse_range_ref(range_ref)
    let (new_min_row, new_min_col, new_max_row, new_max_col) = match axis {
      SqrefRows => {
        let (next_min, next_max) = adjust_bounds_for_insert(
          min_row, max_row, start, count,
        )
        (next_min, min_col, next_max, max_col)
      }
      SqrefColumns => {
        let (next_min, next_max) = adjust_bounds_for_insert(
          min_col, max_col, start, count,
        )
        (min_row, next_min, max_row, next_max)
      }
    }
    let first = cell_ref_from(new_min_row, new_min_col)
    if had_range {
      adjusted.push("\{first}:\{cell_ref_from(new_max_row, new_max_col)}")
    } else {
      adjusted.push(first)
    }
  }
  check_read_cancelled(cancelled)
  adjusted.join(" ")
}

///|
fn adjust_xml_sqref_after_insert(
  xml : StringView,
  start : Int,
  count : Int,
  axis : SqrefInsertAxis,
  cancelled? : () -> Bool = () => false,
) -> String raise XlsxError {
  let tag_text = match tag_attributes_in(xml, "conditionalFormatting") {
    Some(value) => value
    None =>
      match tag_attributes_in(xml, "dataValidation") {
        Some(value) => value
        None => return xml.to_owned()
      }
  }
  let encoded = match attr_value(tag_text, "sqref") {
    Some(value) => value
    None => return xml.to_owned()
  }
  let decoded = decode_structural_sqref(encoded, cancelled~)
  let shifted = adjust_sqref_after_insert(
    decoded,
    start,
    count,
    axis,
    cancelled~,
  )
  match replace_attr_value_in_open_tag(xml, "sqref", shifted) {
    Some(value) => value
    None => raise InvalidXml(msg="sqref update failed")
  }
}

///|
fn adjust_xml_sqrefs_after_insert(
  entries : ArrayView[String],
  start : Int,
  count : Int,
  axis : SqrefInsertAxis,
  cancelled? : () -> Bool = () => false,
) -> Array[String] raise XlsxError {
  let shifted : Array[String] = []
  for index, xml in entries {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    shifted.push(
      adjust_xml_sqref_after_insert(xml, start, count, axis, cancelled~),
    )
  }
  check_read_cancelled(cancelled)
  shifted
}

///|
fn adjust_x14_data_bars_after_insert(
  entries : Map[String, X14DataBarProps],
  start : Int,
  count : Int,
  axis : SqrefInsertAxis,
  cancelled? : () -> Bool = () => false,
) -> Map[String, X14DataBarProps] raise XlsxError {
  let shifted : Map[String, X14DataBarProps] = Map([])
  let mut index = 0
  for id, props in entries {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    shifted[id] = {
      sqref: adjust_sqref_after_insert(
        props.sqref,
        start,
        count,
        axis,
        cancelled~,
      ),
      bar_direction: props.bar_direction,
      bar_solid: props.bar_solid,
      bar_border_color: props.bar_border_color,
    }
    index += 1
  }
  check_read_cancelled(cancelled)
  shifted
}

///|
fn duplicate_sqref_for_row(
  row : Int,
  target_row : Int,
  sqref : StringView,
  cancelled? : () -> Bool = () => false,
) -> Array[String] raise XlsxError {
  let refs : Array[String] = []
  for index, text in xml_whitespace_tokens_cancellable(sqref, cancelled~) {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    if text.length() > 128 {
      raise InvalidXml(msg="sqref reference invalid")
    }
    let (start_ref, end_ref) = split_sqref_range(text)
    let (row1, col1, abs_col1, abs_row1) = parse_cell_ref_with_abs(start_ref)
    let (row2, col2, abs_col2, abs_row2) = parse_cell_ref_with_abs(end_ref)
    if row1 == row2 && row1 == row {
      let from_ref = format_cell_ref_with_abs(
        target_row, col1, abs_col1, abs_row1,
      )
      let to_ref = format_cell_ref_with_abs(
        target_row, col2, abs_col2, abs_row2,
      )
      refs.push("\{from_ref}:\{to_ref}")
    }
  }
  check_read_cancelled(cancelled)
  refs
}

///|

///|
fn duplicate_xml_sqref(
  xml : StringView,
  row : Int,
  target_row : Int,
  cancelled? : () -> Bool = () => false,
) -> String? raise XlsxError {
  let tag_text = match tag_attributes_in(xml, "conditionalFormatting") {
    Some(value) => value
    None =>
      match tag_attributes_in(xml, "dataValidation") {
        Some(value) => value
        None => return None
      }
  }
  let encoded_sqref = match attr_value(tag_text, "sqref") {
    Some(value) => value
    None => return None
  }
  let sqref = decode_structural_sqref(encoded_sqref, cancelled~)
  let refs = duplicate_sqref_for_row(row, target_row, sqref, cancelled~)
  if refs.length() == 0 {
    return None
  }
  let joined = refs.join(" ")
  replace_attr_value_in_open_tag(xml, "sqref", joined)
}

///|
priv struct ConditionalFormatCopies {
  xml : Array[String]
  x14_data_bars : Map[String, X14DataBarProps]
  next_x14_cf_rule_id_counter : Int
}

///|
fn remap_duplicated_x14_ids(
  xml : StringView,
  sqref : String,
  source : Map[String, X14DataBarProps],
  used : Map[String, X14DataBarProps],
  start_counter : Int,
) -> (String, Map[String, X14DataBarProps], Int) raise XlsxError {
  let chunks = Array::from_iter(xml.split(""))
  if chunks.length() <= 1 {
    return (xml.to_owned(), Map([]), start_counter)
  }
  let additions : Map[String, X14DataBarProps] = Map([])
  let builder = StringBuilder::new()
  builder.write_view(chunks[0])
  let mut counter = start_counter
  for index = 1; index < chunks.length(); index = index + 1 {
    let chunk = chunks[index]
    let end = match chunk.find("") {
      Some(value) => value
      None => {
        builder.write_view("")
        builder.write_view(chunk)
        continue
      }
    }
    let encoded_id = chunk[:end]
    let id = @ooxml.decode_xml_attribute(encoded_id) catch {
      InvalidXml(msg~) => raise InvalidXml(msg~)
      ReadCancelled => raise ReadCancelled
    }
    match source.get(id) {
      Some(props) => {
        let (new_id, next_counter) = next_available_x14_cf_rule_id(
          counter, used,
        )
        counter = next_counter
        let duplicated = {
          sqref,
          bar_direction: props.bar_direction,
          bar_solid: props.bar_solid,
          bar_border_color: props.bar_border_color,
        }
        used[new_id] = duplicated
        additions[new_id] = duplicated
        builder.write_view("")
        builder.write_view(escape_xml_text(new_id))
        builder.write_view("")
      }
      None => {
        builder.write_view("")
        builder.write_view(encoded_id)
        builder.write_view("")
      }
    }
    builder.write_view(chunk[end + "".length():])
  }
  (builder.to_string(), additions, counter)
}

///|
fn duplicate_conditional_format_copies(
  entries : ArrayView[String],
  x14_data_bars : Map[String, X14DataBarProps],
  next_x14_cf_rule_id_counter : Int,
  row : Int,
  target_row : Int,
  cancelled? : () -> Bool = () => false,
) -> ConditionalFormatCopies raise XlsxError {
  let copies : Array[String] = []
  let additions : Map[String, X14DataBarProps] = Map([])
  let used : Map[String, X14DataBarProps] = Map([])
  for id, props in x14_data_bars {
    used[id] = props
  }
  let mut counter = next_x14_cf_rule_id_counter
  for index, xml in entries {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    match duplicate_xml_sqref(xml, row, target_row, cancelled~) {
      Some(copy) => {
        let tag = match tag_attributes_in(copy, "conditionalFormatting") {
          Some(value) => value
          None => raise InvalidXml(msg="conditionalFormatting tag missing")
        }
        let encoded_sqref = match attr_value(tag, "sqref") {
          Some(value) => value
          None => raise InvalidXml(msg="conditionalFormatting sqref missing")
        }
        let sqref = decode_structural_sqref(encoded_sqref, cancelled~)
        let (remapped, new_bars, next_counter) = remap_duplicated_x14_ids(
          copy, sqref, x14_data_bars, used, counter,
        )
        counter = next_counter
        for id, props in new_bars {
          additions[id] = props
        }
        copies.push(remapped)
      }
      None => ()
    }
  }
  check_read_cancelled(cancelled)
  {
    xml: copies,
    x14_data_bars: additions,
    next_x14_cf_rule_id_counter: counter,
  }
}

///|
fn duplicate_xml_sqref_copies(
  entries : ArrayView[String],
  row : Int,
  target_row : Int,
  cancelled? : () -> Bool = () => false,
) -> Array[String] raise XlsxError {
  let copies : Array[String] = []
  for index, xml in entries {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    match duplicate_xml_sqref(xml, row, target_row, cancelled~) {
      Some(value) => copies.push(value)
      None => ()
    }
  }
  check_read_cancelled(cancelled)
  copies
}

///|
fn Worksheet::duplicate_data_validations(
  self : Worksheet,
  row : Int,
  target_row : Int,
) -> Unit raise XlsxError {
  let copies = duplicate_xml_sqref_copies(
    self.data_validations,
    row,
    target_row,
  )
  if copies.length() > 0 {
    self.data_validations.append(copies)
  }
}

///|
fn duplicate_merge_cell_copies(
  merged_cells : ArrayView[String],
  row : Int,
  target_row : Int,
  cancelled? : () -> Bool = () => false,
) -> Array[String] raise XlsxError {
  let copies : Array[String] = []
  let mut source_row = row
  if row > target_row {
    source_row = row + 1
  }
  for index, range_ref in merged_cells {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    let (min_row, _min_col, max_row, _max_col) = parse_range_ref(range_ref)
    if min_row < target_row && target_row < max_row {
      return copies
    }
  }
  for index, range_ref in merged_cells {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    let (min_row, min_col, max_row, max_col) = parse_range_ref(range_ref)
    if min_row == max_row && min_row == source_row {
      let from_ref = cell_ref_from(target_row, min_col)
      let to_ref = cell_ref_from(target_row, max_col)
      let duplicate = normalize_range_ref("\{from_ref}:\{to_ref}")
      if !merged_cells.contains(duplicate) && !copies.contains(duplicate) {
        copies.push(duplicate)
      }
    }
  }
  check_read_cancelled(cancelled)
  copies
}

///|
fn Worksheet::duplicate_merge_cells(
  self : Worksheet,
  row : Int,
  target_row : Int,
) -> Unit raise XlsxError {
  let copies = duplicate_merge_cell_copies(self.merged_cells, row, target_row)
  self.merged_cells.append(copies)
}

///|
fn Worksheet::duplicate_row_to(
  self : Worksheet,
  row : Int,
  target_row : Int,
  formula_limits? : SharedFormulaLimits = SharedFormulaLimits::new(),
  cancelled? : () -> Bool = () => false,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if row <= 0 || row > cell_ref_max_rows {
    raise InvalidCellRef(value="\{0}:\{row}")
  }
  if target_row <= 0 || row == target_row {
    raise InvalidSheetOperation(msg="duplicate row target must be different")
  }
  // The copy lands at `target_row`, so it must be an in-grid row (otherwise the
  // duplicate would write an out-of-grid reference like A1048577).
  if target_row > cell_ref_max_rows {
    raise InvalidCellRef(value="\{0}:\{target_row}")
  }
  let translation_budget = SharedFormulaMaterializationBudget::new(
    formula_limits,
    cancelled~,
  )
  let shared_formula_masters = validated_shared_formula_masters(
    self.cells,
    cancelled=translation_budget.cancelled,
  )
  preflight_shared_formula_materialization(
    self.cells,
    shared_formula_masters,
    translation_budget,
    fn(cell : Cell) -> Bool { cell.row == row },
  )
  // Stage every fallible derivative before `insert_rows` commits its own
  // transactional shift. Once that insert succeeds, the remaining appends and
  // map assignments below are infallible state installation.
  let duplicated_cells : Array[Cell] = []
  for index, stored_cell in self.cells {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    if stored_cell.row != row {
      continue
    }
    let cell = normal_formula_cell_for_structural_edit(
      stored_cell, shared_formula_masters, translation_budget,
    )
    let reference = cell_ref_from(target_row, cell.col)
    duplicated_cells.push({
      reference,
      row: target_row,
      col: cell.col,
      value: cell.value,
      value_type: cell.value_type,
      rich_text: cell.rich_text,
      formula: cell.formula,
      formula_type: cell.formula_type,
      formula_ref: cell.formula_ref,
      formula_shared_index: cell.formula_shared_index,
      formula_value_present: cell.formula_value_present,
      style_explicit: cell.style_explicit,
      style_id: cell.style_id,
    })
  }
  let row_dim = self.row_dimensions.get(row)
  let conditional_format_copies = duplicate_conditional_format_copies(
    self.conditional_formats,
    self.x14_data_bars,
    self.x14_cf_rule_id_counter,
    row,
    target_row,
    cancelled=translation_budget.cancelled,
  )
  let data_validation_copies = duplicate_xml_sqref_copies(
    self.data_validations,
    row,
    target_row,
    cancelled=translation_budget.cancelled,
  )
  let shifted_merges : Array[String] = []
  for index, range_ref in self.merged_cells {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    shifted_merges.push(adjust_range_after_row_insert(range_ref, target_row, 1))
  }
  let merge_copies = duplicate_merge_cell_copies(
    shifted_merges,
    row,
    target_row,
    cancelled=translation_budget.cancelled,
  )
  translation_budget.checkpoint()
  self.insert_rows(
    target_row,
    1,
    formula_limits~,
    cancelled~,
    formula_budget=translation_budget,
  )
  self.cells.append(duplicated_cells)
  match row_dim {
    Some(dim) =>
      if row_dimension_is_default(dim) {
        self.row_dimensions.remove(target_row)
      } else {
        self.row_dimensions[target_row] = dim
      }
    None => self.row_dimensions.remove(target_row)
  }
  self.conditional_formats.append(conditional_format_copies.xml)
  for id, props in conditional_format_copies.x14_data_bars {
    self.x14_data_bars[id] = props
  }
  self.x14_cf_rule_id_counter = conditional_format_copies.next_x14_cf_rule_id_counter
  self.data_validations.append(data_validation_copies)
  self.merged_cells.append(merge_copies)
}

///|
fn Worksheet::insert_cols(
  self : Worksheet,
  col : Int,
  count : Int,
  formula_limits? : SharedFormulaLimits = SharedFormulaLimits::new(),
  cancelled? : () -> Bool = () => false,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if col <= 0 || col > cell_ref_max_cols {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  if count <= 0 {
    raise InvalidSheetOperation(msg="column count must be positive")
  }
  // A count larger than the grid would let `existing_col + count` wrap `Int`.
  if count > cell_ref_max_cols {
    raise InvalidSheetOperation(
      msg="column count \{count} exceeds the sheet's \{cell_ref_max_cols} columns",
    )
  }
  let translation_budget = SharedFormulaMaterializationBudget::new(
    formula_limits,
    cancelled~,
  )
  let shared_formula_masters = validated_shared_formula_masters(
    self.cells,
    cancelled=translation_budget.cancelled,
  )
  preflight_shared_formula_materialization(
    self.cells,
    shared_formula_masters,
    translation_budget,
    fn(_cell : Cell) -> Bool { true },
  )
  translation_budget.checkpoint()
  // Transactional (see insert_rows): stage everything into locals — including
  // conditional-format and validation sqrefs. Reference shifts raise once a
  // coordinate leaves the grid, column dimensions and page breaks are
  // bound-checked explicitly, and the state commits only after every stage has
  // succeeded.
  let updated_cells : Array[Cell] = []
  for index, stored_cell in self.cells {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let cell = normal_formula_cell_for_structural_edit(
      stored_cell, shared_formula_masters, translation_budget,
    )
    if cell.col >= col {
      let new_col = cell.col + count
      let reference = cell_ref_from(cell.row, new_col)
      updated_cells.push({
        reference,
        row: cell.row,
        col: new_col,
        value: cell.value,
        value_type: cell.value_type,
        rich_text: cell.rich_text,
        formula: cell.formula,
        formula_type: cell.formula_type,
        formula_ref: cell.formula_ref,
        formula_shared_index: cell.formula_shared_index,
        formula_value_present: cell.formula_value_present,
        style_explicit: cell.style_explicit,
        style_id: cell.style_id,
      })
    } else {
      updated_cells.push(cell)
    }
  }
  let updated_merges : Array[String] = []
  for index, range_ref in self.merged_cells {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    updated_merges.push(adjust_range_after_col_insert(range_ref, col, count))
  }
  let updated_conditional_formats = adjust_xml_sqrefs_after_insert(
    self.conditional_formats,
    col,
    count,
    SqrefColumns,
    cancelled=translation_budget.cancelled,
  )
  let updated_x14_data_bars = adjust_x14_data_bars_after_insert(
    self.x14_data_bars,
    col,
    count,
    SqrefColumns,
    cancelled=translation_budget.cancelled,
  )
  let updated_data_validations = adjust_xml_sqrefs_after_insert(
    self.data_validations,
    col,
    count,
    SqrefColumns,
    cancelled=translation_budget.cancelled,
  )
  let updated_links : Array[Hyperlink] = []
  for index, link in self.hyperlinks {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let reference = adjust_hyperlink_ref_after_col_insert(
      link.reference,
      col,
      count,
    )
    updated_links.push({
      reference,
      target: link.target,
      link_type: link.link_type,
      location: link.location,
      display: link.display,
      tooltip: link.tooltip,
    })
  }
  translation_budget.checkpoint()
  let updated_filter = match self.auto_filter {
    Some(filter) =>
      Some(adjust_auto_filter_after_col_insert(filter, col, count))
    None => None
  }
  let updated_tables : Array[Table] = []
  for index, table in self.tables {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    updated_tables.push(
      adjust_table_after_col_insert(
        table,
        col,
        count,
        cancelled=translation_budget.cancelled,
      ),
    )
  }
  let updated_sparklines : Array[SparklineGroup] = []
  for index, group in self.sparkline_groups {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let adjusted = adjust_sparkline_group_after_col_insert(
      group,
      col,
      count,
      cancelled=translation_budget.cancelled,
    )
    if adjusted.sparklines.length() > 0 {
      updated_sparklines.push(adjusted)
    }
  }
  let updated_images : Array[Image] = []
  for index, image in self.images {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let reference = adjust_cell_after_col_insert(image.reference, col, count)
    updated_images.push(image_with_reference(image, reference))
  }
  let updated_charts : Array[Chart] = []
  for index, chart in self.charts {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let reference = adjust_cell_after_col_insert(chart.reference, col, count)
    updated_charts.push(chart_with_reference(chart, reference))
  }
  let updated_cols : Map[Int, ColDimension] = Map([])
  let mut dimension_index = 0
  for col_index, dim in self.col_dimensions {
    if (dimension_index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let new_col = if col_index >= col {
      // Overflow-safe (see insert_rows): stored keys are not bounded by their
      // setters, so validate before the addition.
      if col_index > cell_ref_max_cols - count {
        raise InvalidCellRef(value="\{col_index}:\{0}")
      }
      col_index + count
    } else {
      col_index
    }
    updated_cols[new_col] = dim
    dimension_index += 1
  }
  let break_start = col - 1
  // 0-based ids (see insert_rows): validate overflow-safely before the shift.
  for index, brk in self.col_breaks {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    if brk.id >= break_start && brk.id > cell_ref_max_cols - 1 - count {
      raise InvalidCellRef(value="\{brk.id}:\{0}")
    }
  }
  let updated_breaks = adjust_page_breaks_after_insert(
    self.col_breaks,
    break_start,
    count,
    cancelled=translation_budget.cancelled,
  )
  // Commit.
  translation_budget.checkpoint()
  self.invalidate_shared_formula_masters_index()
  self.invalidate_cell_index()
  self.cells.clear()
  self.cells.append(updated_cells)
  self.merged_cells.clear()
  self.merged_cells.append(updated_merges)
  self.conditional_formats.clear()
  self.conditional_formats.append(updated_conditional_formats)
  self.x14_data_bars.clear()
  for id, props in updated_x14_data_bars {
    self.x14_data_bars[id] = props
  }
  self.data_validations.clear()
  self.data_validations.append(updated_data_validations)
  self.hyperlinks.clear()
  self.hyperlinks.append(updated_links)
  self.auto_filter = updated_filter
  self.tables.clear()
  self.tables.append(updated_tables)
  self.sparkline_groups.clear()
  self.sparkline_groups.append(updated_sparklines)
  self.images.clear()
  self.images.append(updated_images)
  self.charts.clear()
  self.charts.append(updated_charts)
  self.col_dimensions.clear()
  for col_index, dim in updated_cols {
    self.col_dimensions[col_index] = dim
  }
  self.col_breaks.clear()
  self.col_breaks.append(updated_breaks)
}

///|
fn Worksheet::remove_cols(
  self : Worksheet,
  col : Int,
  count : Int,
  formula_limits? : SharedFormulaLimits = SharedFormulaLimits::new(),
  cancelled? : () -> Bool = () => false,
) -> Unit raise XlsxError {
  self.ensure_stream_idle()
  if col <= 0 {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  if count <= 0 {
    raise InvalidSheetOperation(msg="column count must be positive")
  }
  // Bound both the start and the count so `col + count - 1` cannot wrap `Int`.
  if col > cell_ref_max_cols {
    raise InvalidCellRef(value="\{col}:\{0}")
  }
  if count > cell_ref_max_cols {
    raise InvalidSheetOperation(
      msg="column count \{count} exceeds the sheet's \{cell_ref_max_cols} columns",
    )
  }
  let translation_budget = SharedFormulaMaterializationBudget::new(
    formula_limits,
    cancelled~,
  )
  let shared_formula_masters = validated_shared_formula_masters(
    self.cells,
    cancelled=translation_budget.cancelled,
  )
  let end_col = col + count - 1
  preflight_shared_formula_materialization(
    self.cells,
    shared_formula_masters,
    translation_budget,
    fn(cell : Cell) -> Bool { cell.col < col || cell.col > end_col },
  )
  translation_budget.checkpoint()
  let updated_cells : Array[Cell] = []
  for index, stored_cell in self.cells {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    if stored_cell.col >= col && stored_cell.col <= end_col {
      continue
    }
    let cell = normal_formula_cell_for_structural_edit(
      stored_cell, shared_formula_masters, translation_budget,
    )
    if cell.col < col {
      updated_cells.push(cell)
      continue
    }
    let new_col = cell.col - count
    let reference = cell_ref_from(cell.row, new_col)
    updated_cells.push({
      reference,
      row: cell.row,
      col: new_col,
      value: cell.value,
      value_type: cell.value_type,
      rich_text: cell.rich_text,
      formula: cell.formula,
      formula_type: cell.formula_type,
      formula_ref: cell.formula_ref,
      formula_shared_index: cell.formula_shared_index,
      formula_value_present: cell.formula_value_present,
      style_explicit: cell.style_explicit,
      style_id: cell.style_id,
    })
  }
  let updated_merges : Array[String] = []
  for index, range_ref in self.merged_cells {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    match adjust_range_after_col_remove(range_ref, col, count) {
      Some(value) => updated_merges.push(value)
      None => ()
    }
  }
  let updated_links : Array[Hyperlink] = []
  for index, link in self.hyperlinks {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    match adjust_hyperlink_ref_after_col_remove(link.reference, col, count) {
      Some(reference) =>
        updated_links.push({
          reference,
          target: link.target,
          link_type: link.link_type,
          location: link.location,
          display: link.display,
          tooltip: link.tooltip,
        })
      None => ()
    }
  }
  translation_budget.checkpoint()
  let updated_filter = match self.auto_filter {
    Some(filter) =>
      match adjust_auto_filter_after_col_remove(filter, col, count) {
        Some(updated) => Some(updated)
        None => None
      }
    None => None
  }
  let updated_tables : Array[Table] = []
  for index, table in self.tables {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    match
      adjust_table_after_col_remove(
        table,
        col,
        count,
        cancelled=translation_budget.cancelled,
      ) {
      Some(value) => updated_tables.push(value)
      None => ()
    }
  }
  let updated_sparklines : Array[SparklineGroup] = []
  for index, group in self.sparkline_groups {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    let adjusted = adjust_sparkline_group_after_col_remove(
      group,
      col,
      count,
      cancelled=translation_budget.cancelled,
    )
    if adjusted.sparklines.length() > 0 {
      updated_sparklines.push(adjusted)
    }
  }
  let updated_images : Array[Image] = []
  for index, image in self.images {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    match adjust_cell_after_col_remove(image.reference, col, count) {
      Some(reference) =>
        updated_images.push(image_with_reference(image, reference))
      None => ()
    }
  }
  let updated_charts : Array[Chart] = []
  for index, chart in self.charts {
    if (index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    match adjust_cell_after_col_remove(chart.reference, col, count) {
      Some(reference) =>
        updated_charts.push(chart_with_reference(chart, reference))
      None => ()
    }
  }
  let updated_cols : Map[Int, ColDimension] = Map([])
  let mut dimension_index = 0
  for col_index, dim in self.col_dimensions {
    if (dimension_index & 4095) == 0 {
      translation_budget.checkpoint()
    }
    if col_index < col {
      updated_cols[col_index] = dim
    } else if col_index > end_col {
      updated_cols[col_index - count] = dim
    }
    dimension_index += 1
  }
  let break_start = col - 1
  let updated_breaks = adjust_page_breaks_after_remove(
    self.col_breaks,
    break_start,
    count,
    cancelled=translation_budget.cancelled,
  )
  translation_budget.checkpoint()
  self.invalidate_shared_formula_masters_index()
  self.invalidate_cell_index()
  self.cells.clear()
  self.cells.append(updated_cells)
  self.merged_cells.clear()
  self.merged_cells.append(updated_merges)
  self.hyperlinks.clear()
  self.hyperlinks.append(updated_links)
  self.auto_filter = updated_filter
  self.tables.clear()
  self.tables.append(updated_tables)
  self.sparkline_groups.clear()
  self.sparkline_groups.append(updated_sparklines)
  self.images.clear()
  self.images.append(updated_images)
  self.charts.clear()
  self.charts.append(updated_charts)
  self.col_dimensions.clear()
  for col_index, dim in updated_cols {
    self.col_dimensions[col_index] = dim
  }
  self.col_breaks.clear()
  self.col_breaks.append(updated_breaks)
}

///|
fn adjust_bounds_for_insert(
  raw_min : Int,
  raw_max : Int,
  start : Int,
  count : Int,
) -> (Int, Int) {
  // Order-aware: a defined-name range can be stored reversed (e.g. `$A$5:$A$1`).
  // Normalize to [min, max] before shifting so the result stays in-grid rather
  // than producing a bogus endpoint.
  let min = if raw_min <= raw_max { raw_min } else { raw_max }
  let max = if raw_min <= raw_max { raw_max } else { raw_min }
  if start <= min {
    (min + count, max + count)
  } else if start <= max {
    (min, max + count)
  } else {
    (min, max)
  }
}

///|
fn adjust_bounds_for_remove(
  raw_min : Int,
  raw_max : Int,
  start : Int,
  count : Int,
) -> (Int, Int)? {
  // Order-aware (see adjust_bounds_for_insert): normalize a reversed range so a
  // removal never yields a negative/out-of-order endpoint.
  let min = if raw_min <= raw_max { raw_min } else { raw_max }
  let max = if raw_min <= raw_max { raw_max } else { raw_min }
  let end = start + count - 1
  if end < min {
    return Some((min - count, max - count))
  }
  if start > max {
    return Some((min, max))
  }
  let removed_before = if start < min { min - start } else { 0 }
  let overlap_start = if start > min { start } else { min }
  let overlap_end = if end < max { end } else { max }
  let removed_inside = overlap_end - overlap_start + 1
  let new_min = min - removed_before
  let new_max = max - removed_before - removed_inside
  if new_max < new_min {
    None
  } else {
    Some((new_min, new_max))
  }
}

///|
fn adjust_page_breaks_after_insert(
  breaks : Array[PageBreak],
  start : Int,
  count : Int,
  cancelled? : () -> Bool = () => false,
) -> Array[PageBreak] raise XlsxError {
  let updated : Array[PageBreak] = []
  for index, brk in breaks {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    let new_id = if brk.id >= start { brk.id + count } else { brk.id }
    updated.push({ id: new_id, min: brk.min, max: brk.max, manual: brk.manual })
  }
  check_read_cancelled(cancelled)
  updated
}

///|
fn adjust_page_breaks_after_remove(
  breaks : Array[PageBreak],
  start : Int,
  count : Int,
  cancelled? : () -> Bool = () => false,
) -> Array[PageBreak] raise XlsxError {
  let updated : Array[PageBreak] = []
  let end = start + count - 1
  for index, brk in breaks {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    if brk.id < start {
      updated.push(brk)
      continue
    }
    if brk.id > end {
      updated.push({
        id: brk.id - count,
        min: brk.min,
        max: brk.max,
        manual: brk.manual,
      })
    }
  }
  check_read_cancelled(cancelled)
  updated
}

///|
fn adjust_range_after_row_insert(
  range_ref : String,
  row : Int,
  count : Int,
) -> String raise XlsxError {
  let (min_row, min_col, max_row, max_col) = parse_range_ref(range_ref)
  let (new_min_row, new_max_row) = adjust_bounds_for_insert(
    min_row, max_row, row, count,
  )
  let start_ref = cell_ref_from(new_min_row, min_col)
  let end_ref = cell_ref_from(new_max_row, max_col)
  "\{start_ref}:\{end_ref}"
}

///|
fn adjust_range_after_row_remove(
  range_ref : String,
  row : Int,
  count : Int,
) -> String? raise XlsxError {
  let (min_row, min_col, max_row, max_col) = parse_range_ref(range_ref)
  match adjust_bounds_for_remove(min_row, max_row, row, count) {
    Some((new_min_row, new_max_row)) => {
      let start_ref = cell_ref_from(new_min_row, min_col)
      let end_ref = cell_ref_from(new_max_row, max_col)
      Some("\{start_ref}:\{end_ref}")
    }
    None => None
  }
}

///|
fn adjust_range_after_col_insert(
  range_ref : String,
  col : Int,
  count : Int,
) -> String raise XlsxError {
  let (min_row, min_col, max_row, max_col) = parse_range_ref(range_ref)
  let (new_min_col, new_max_col) = adjust_bounds_for_insert(
    min_col, max_col, col, count,
  )
  let start_ref = cell_ref_from(min_row, new_min_col)
  let end_ref = cell_ref_from(max_row, new_max_col)
  "\{start_ref}:\{end_ref}"
}

///|
fn adjust_range_after_col_remove(
  range_ref : String,
  col : Int,
  count : Int,
) -> String? raise XlsxError {
  let (min_row, min_col, max_row, max_col) = parse_range_ref(range_ref)
  match adjust_bounds_for_remove(min_col, max_col, col, count) {
    Some((new_min_col, new_max_col)) => {
      let start_ref = cell_ref_from(min_row, new_min_col)
      let end_ref = cell_ref_from(max_row, new_max_col)
      Some("\{start_ref}:\{end_ref}")
    }
    None => None
  }
}

///|
fn adjust_auto_filter_after_row_insert(
  filter : AutoFilter,
  row : Int,
  count : Int,
) -> AutoFilter raise XlsxError {
  let range_ref = adjust_range_after_row_insert(filter.range_ref, row, count)
  let copied = clone_auto_filter(filter)
  { range_ref, columns: copied.columns }
}

///|
fn adjust_auto_filter_after_row_remove(
  filter : AutoFilter,
  row : Int,
  count : Int,
) -> AutoFilter? raise XlsxError {
  match adjust_range_after_row_remove(filter.range_ref, row, count) {
    Some(range_ref) => {
      let copied = clone_auto_filter(filter)
      Some({ range_ref, columns: copied.columns })
    }
    None => None
  }
}

///|
fn adjust_auto_filter_after_col_insert(
  filter : AutoFilter,
  col : Int,
  count : Int,
) -> AutoFilter raise XlsxError {
  let range_ref = adjust_range_after_col_insert(filter.range_ref, col, count)
  let columns : Array[AutoFilterColumn] = []
  for entry in filter.columns {
    let updated_col = if entry.col >= col {
      entry.col + count
    } else {
      entry.col
    }
    columns.push({
      col: updated_col,
      filters: entry.filters,
      custom_filters: entry.custom_filters,
    })
  }
  { range_ref, columns }
}

///|
fn adjust_auto_filter_after_col_remove(
  filter : AutoFilter,
  col : Int,
  count : Int,
) -> AutoFilter? raise XlsxError {
  let end = col + count - 1
  match adjust_range_after_col_remove(filter.range_ref, col, count) {
    Some(range_ref) => {
      let columns : Array[AutoFilterColumn] = []
      for entry in filter.columns {
        if entry.col >= col && entry.col <= end {
          continue
        }
        let updated_col = if entry.col > end {
          entry.col - count
        } else {
          entry.col
        }
        columns.push({
          col: updated_col,
          filters: entry.filters,
          custom_filters: entry.custom_filters,
        })
      }
      Some({ range_ref, columns })
    }
    None => None
  }
}

///|
fn adjust_hyperlink_ref_after_row_insert(
  reference : String,
  row : Int,
  count : Int,
) -> String raise XlsxError {
  if reference.contains(":") {
    adjust_range_after_row_insert(reference, row, count)
  } else {
    adjust_cell_after_row_insert(reference, row, count)
  }
}

///|
fn adjust_hyperlink_ref_after_row_remove(
  reference : String,
  row : Int,
  count : Int,
) -> String? raise XlsxError {
  if reference.contains(":") {
    adjust_range_after_row_remove(reference, row, count)
  } else {
    adjust_cell_after_row_remove(reference, row, count)
  }
}

///|
fn adjust_hyperlink_ref_after_col_insert(
  reference : String,
  col : Int,
  count : Int,
) -> String raise XlsxError {
  if reference.contains(":") {
    adjust_range_after_col_insert(reference, col, count)
  } else {
    adjust_cell_after_col_insert(reference, col, count)
  }
}

///|
fn adjust_hyperlink_ref_after_col_remove(
  reference : String,
  col : Int,
  count : Int,
) -> String? raise XlsxError {
  if reference.contains(":") {
    adjust_range_after_col_remove(reference, col, count)
  } else {
    adjust_cell_after_col_remove(reference, col, count)
  }
}

///|
fn adjust_cell_after_row_insert(
  reference : String,
  row : Int,
  count : Int,
) -> String raise XlsxError {
  let (cell_row, cell_col) = cell_ref_to_rc(reference)
  let new_row = if cell_row >= row { cell_row + count } else { cell_row }
  cell_ref_from(new_row, cell_col)
}

///|
fn adjust_cell_after_row_remove(
  reference : String,
  row : Int,
  count : Int,
) -> String? raise XlsxError {
  let (cell_row, cell_col) = cell_ref_to_rc(reference)
  let end_row = row + count - 1
  if cell_row < row {
    Some(cell_ref_from(cell_row, cell_col))
  } else if cell_row <= end_row {
    None
  } else {
    Some(cell_ref_from(cell_row - count, cell_col))
  }
}

///|
fn adjust_cell_after_col_insert(
  reference : String,
  col : Int,
  count : Int,
) -> String raise XlsxError {
  let (cell_row, cell_col) = cell_ref_to_rc(reference)
  let new_col = if cell_col >= col { cell_col + count } else { cell_col }
  cell_ref_from(cell_row, new_col)
}

///|
fn adjust_cell_after_col_remove(
  reference : String,
  col : Int,
  count : Int,
) -> String? raise XlsxError {
  let (cell_row, cell_col) = cell_ref_to_rc(reference)
  let end_col = col + count - 1
  if cell_col < col {
    Some(cell_ref_from(cell_row, cell_col))
  } else if cell_col <= end_col {
    None
  } else {
    Some(cell_ref_from(cell_row, cell_col - count))
  }
}

///|
fn clone_table_columns(
  columns : ArrayView[String],
  cancelled? : () -> Bool = () => false,
) -> Array[String] raise XlsxError {
  let out : Array[String] = []
  for index, column in columns {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    out.push(column)
  }
  check_read_cancelled(cancelled)
  out
}

///|
fn table_default_column_name(index : Int) -> String {
  "Column\{index}"
}

///|
fn adjust_table_after_row_insert(
  table : Table,
  row : Int,
  count : Int,
  cancelled? : () -> Bool = () => false,
) -> Table raise XlsxError {
  let range_ref = adjust_range_after_row_insert(table.range_ref, row, count)
  {
    id: table.id,
    name: table.name,
    display_name: table.display_name,
    range: range_ref,
    range_ref,
    columns: clone_table_columns(table.columns, cancelled~),
    style_name: table.style_name,
    show_first_column: table.show_first_column,
    show_last_column: table.show_last_column,
    show_row_stripes: table.show_row_stripes,
    show_column_stripes: table.show_column_stripes,
    show_header_row: table.show_header_row,
    carries_source_formulas: table.carries_source_formulas,
  }
}

///|
fn adjust_table_after_row_remove(
  table : Table,
  row : Int,
  count : Int,
  cancelled? : () -> Bool = () => false,
) -> Table? raise XlsxError {
  match adjust_range_after_row_remove(table.range_ref, row, count) {
    Some(range_ref) =>
      Some({
        id: table.id,
        name: table.name,
        display_name: table.display_name,
        range: range_ref,
        range_ref,
        columns: clone_table_columns(table.columns, cancelled~),
        style_name: table.style_name,
        show_first_column: table.show_first_column,
        show_last_column: table.show_last_column,
        show_row_stripes: table.show_row_stripes,
        show_column_stripes: table.show_column_stripes,
        show_header_row: table.show_header_row,
        carries_source_formulas: table.carries_source_formulas,
      })
    None => None
  }
}

///|
fn adjust_table_after_col_insert(
  table : Table,
  col : Int,
  count : Int,
  cancelled? : () -> Bool = () => false,
) -> Table raise XlsxError {
  let (min_row, min_col, max_row, max_col) = parse_range_ref(table.range_ref)
  let (new_min_col, new_max_col) = adjust_bounds_for_insert(
    min_col, max_col, col, count,
  )
  let columns = clone_table_columns(table.columns, cancelled~)
  if col > min_col && col <= max_col {
    let insert_index = col - min_col
    let base = columns.length() + 1
    let mut i = 0
    while i < count {
      if (i & 4095) == 0 {
        check_read_cancelled(cancelled)
      }
      columns.insert(insert_index + i, table_default_column_name(base + i))
      i = i + 1
    }
  }
  let start_ref = cell_ref_from(min_row, new_min_col)
  let end_ref = cell_ref_from(max_row, new_max_col)
  {
    id: table.id,
    name: table.name,
    display_name: table.display_name,
    range: "\{start_ref}:\{end_ref}",
    range_ref: "\{start_ref}:\{end_ref}",
    columns,
    style_name: table.style_name,
    show_first_column: table.show_first_column,
    show_last_column: table.show_last_column,
    show_row_stripes: table.show_row_stripes,
    show_column_stripes: table.show_column_stripes,
    show_header_row: table.show_header_row,
    carries_source_formulas: table.carries_source_formulas,
  }
}

///|
fn adjust_table_after_col_remove(
  table : Table,
  col : Int,
  count : Int,
  cancelled? : () -> Bool = () => false,
) -> Table? raise XlsxError {
  let (min_row, min_col, max_row, max_col) = parse_range_ref(table.range_ref)
  match adjust_bounds_for_remove(min_col, max_col, col, count) {
    Some((new_min_col, new_max_col)) => {
      let columns = clone_table_columns(table.columns, cancelled~)
      let end_col = col + count - 1
      if !(end_col < min_col || col > max_col) {
        let overlap_start = if col > min_col { col } else { min_col }
        let overlap_end = if end_col < max_col { end_col } else { max_col }
        let remove_count = overlap_end - overlap_start + 1
        let remove_index = overlap_start - min_col
        let mut i = 0
        while i < remove_count {
          if (i & 4095) == 0 {
            check_read_cancelled(cancelled)
          }
          ignore(columns.remove(remove_index))
          i = i + 1
        }
      }
      let start_ref = cell_ref_from(min_row, new_min_col)
      let end_ref = cell_ref_from(max_row, new_max_col)
      Some({
        id: table.id,
        name: table.name,
        display_name: table.display_name,
        range: "\{start_ref}:\{end_ref}",
        range_ref: "\{start_ref}:\{end_ref}",
        columns,
        style_name: table.style_name,
        show_first_column: table.show_first_column,
        show_last_column: table.show_last_column,
        show_row_stripes: table.show_row_stripes,
        show_column_stripes: table.show_column_stripes,
        show_header_row: table.show_header_row,
        carries_source_formulas: table.carries_source_formulas,
      })
    }
    None => None
  }
}

///|
fn adjust_sparkline_group_after_row_insert(
  group : SparklineGroup,
  row : Int,
  count : Int,
  cancelled? : () -> Bool = () => false,
) -> SparklineGroup raise XlsxError {
  let updated : Array[Sparkline] = []
  for index, sparkline in group.sparklines {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    let range_ref = adjust_range_after_row_insert(
      sparkline.range_ref,
      row,
      count,
    )
    let location = adjust_cell_after_row_insert(sparkline.location, row, count)
    updated.push({ range_ref, location })
  }
  {
    sparkline_type: group.sparkline_type,
    sparklines: updated,
    options: group.options,
  }
}

///|
fn adjust_sparkline_group_after_row_remove(
  group : SparklineGroup,
  row : Int,
  count : Int,
  cancelled? : () -> Bool = () => false,
) -> SparklineGroup raise XlsxError {
  let updated : Array[Sparkline] = []
  for index, sparkline in group.sparklines {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    let range_ref = adjust_range_after_row_remove(
      sparkline.range_ref,
      row,
      count,
    )
    let location = adjust_cell_after_row_remove(sparkline.location, row, count)
    match (range_ref, location) {
      (Some(range_ref), Some(location)) => updated.push({ range_ref, location })
      _ => ()
    }
  }
  {
    sparkline_type: group.sparkline_type,
    sparklines: updated,
    options: group.options,
  }
}

///|
fn adjust_sparkline_group_after_col_insert(
  group : SparklineGroup,
  col : Int,
  count : Int,
  cancelled? : () -> Bool = () => false,
) -> SparklineGroup raise XlsxError {
  let updated : Array[Sparkline] = []
  for index, sparkline in group.sparklines {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    let range_ref = adjust_range_after_col_insert(
      sparkline.range_ref,
      col,
      count,
    )
    let location = adjust_cell_after_col_insert(sparkline.location, col, count)
    updated.push({ range_ref, location })
  }
  {
    sparkline_type: group.sparkline_type,
    sparklines: updated,
    options: group.options,
  }
}

///|
fn adjust_sparkline_group_after_col_remove(
  group : SparklineGroup,
  col : Int,
  count : Int,
  cancelled? : () -> Bool = () => false,
) -> SparklineGroup raise XlsxError {
  let updated : Array[Sparkline] = []
  for index, sparkline in group.sparklines {
    if (index & 4095) == 0 {
      check_read_cancelled(cancelled)
    }
    let range_ref = adjust_range_after_col_remove(
      sparkline.range_ref,
      col,
      count,
    )
    let location = adjust_cell_after_col_remove(sparkline.location, col, count)
    match (range_ref, location) {
      (Some(range_ref), Some(location)) => updated.push({ range_ref, location })
      _ => ()
    }
  }
  {
    sparkline_type: group.sparkline_type,
    sparklines: updated,
    options: group.options,
  }
}

///|
fn compare_cell(a : Cell, b : Cell) -> Int {
  if a.row != b.row {
    a.row - b.row
  } else {
    a.col - b.col
  }
}

///|
fn sort_cells(cells : Array[Cell]) -> Unit {
  let mut i = 1
  while i < cells.length() {
    let key = cells[i]
    let mut j = i - 1
    for state = true {
      if !state {
        break
      }
      if j < 0 || compare_cell(cells[j], key) <= 0 {
        continue false
      }
      cells[j + 1] = cells[j]
      j = j - 1
      continue true
    }
    cells[j + 1] = key
    i = i + 1
  }
}

///|
test "worksheet wb: missing-cell getters return None" {
  let sheet = Worksheet::new("Sheet1")
  debug_inspect(sheet.get_cell_rich_text("Z99"), content="None")
  debug_inspect(sheet.get_cell_formula("Z99"), content="None")
  debug_inspect(sheet.get_cell_style("Z99"), content="None")
  debug_inspect(sheet.get_cell_style_rc(99, 26), content="None")
}

///|
test "worksheet wb: set_state updates worksheet visibility state" {
  let sheet = Worksheet::new("Sheet1")
  debug_inspect(sheet.state(), content="Visible")
  sheet.state = Hidden
  debug_inspect(sheet.state(), content="Hidden")
  sheet.state = VeryHidden
  debug_inspect(sheet.state(), content="VeryHidden")
}

///|
test "worksheet wb: sparkline and validation guard errors" {
  let sheet = Worksheet::new("Sheet1")
  let empty_inputs : Result[Unit, Error] = Ok(sheet.add_sparkline_group([], [])) catch {
    e => Err(e)
  }
  debug_inspect(
    empty_inputs,
    content=(
      #|Err(InvalidSparkline(msg="sparkline inputs empty"))
    ),
  )
  let empty_list : Result[Unit, Error] = Ok(
    sheet.add_data_validation_list("A1", []),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    empty_list,
    content=(
      #|Err(UnsupportedFeature(msg="empty validation list"))
    ),
  )
}

///|
test "worksheet wb: delete_slicer empty/missing/remove branches" {
  let sheet = Worksheet::new("Sheet1")
  let empty_name : Result[Unit, Error] = Ok(sheet.delete_slicer("")) catch {
    e => Err(e)
  }
  debug_inspect(
    empty_name,
    content=(
      #|Err(InvalidSheetOperation(msg="slicer name empty"))
    ),
  )
  let missing : Result[Unit, Error] = Ok(sheet.delete_slicer("Missing")) catch {
    e => Err(e)
  }
  debug_inspect(
    missing,
    content=(
      #|Err(InvalidSheetOperation(msg="slicer not found"))
    ),
  )

  let region = Slicer::new("Region") catch {
    err => fail("slicer init failed: \{repr(err)}")
  }
  let typ = Slicer::new("Type") catch {
    err => fail("slicer init failed: \{repr(err)}")
  }
  sheet.add_slicer(region)
  sheet.add_slicer(typ)
  sheet.delete_slicer("Region")
  let slicers = sheet.get_slicers()
  inspect(slicers.length(), content="1")
  inspect(slicers[0].name, content="Type")
}

///|
test "worksheet wb: data validation append/clear/error branches" {
  let sheet = Worksheet::new("Sheet1")
  let dv = DataValidation::new(true)
  dv.set_sqref("A1")
  dv.set_drop_list(["Yes"])
  sheet.add_data_validation_xml(data_validation_xml(dv))
  inspect(sheet.get_data_validations().length(), content="1")
  sheet.delete_data_validation()
  inspect(sheet.get_data_validations().length(), content="0")

  let dropped = Worksheet::new("Sheet1")
  let dv_drop = DataValidation::new(true)
  dv_drop.set_sqref("B2")
  dv_drop.set_drop_list(["No"])
  dropped.add_data_validation_xml(data_validation_xml(dv_drop))
  dropped.delete_data_validation(sqrefs=["B2"])
  inspect(dropped.get_data_validations().length(), content="0")

  let missing_tag = Worksheet::new("Sheet1")
  missing_tag.add_data_validation_xml("")
  let missing_tag_result : Result[Unit, Error] = Ok(
    missing_tag.delete_data_validation(sqrefs=["A1"]),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    missing_tag_result,
    content=(
      #|Err(InvalidXml(msg="data validation tag missing"))
    ),
  )

  let missing_sqref = Worksheet::new("Sheet1")
  missing_sqref.add_data_validation_xml(
    "\"Y\"",
  )
  let missing_sqref_result : Result[Unit, Error] = Ok(
    missing_sqref.delete_data_validation(sqrefs=["A1"]),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    missing_sqref_result,
    content=(
      #|Err(InvalidXml(msg="data validation sqref missing"))
    ),
  )
}

///|
test "worksheet wb: pivot-table wrapper and picture/header-footer guards" {
  let sheet = Worksheet::new("Sheet1")
  ignore(
    sheet.add_pivot_table_xml(
      "",
      "",
      name="Pivot1",
    ),
  )
  inspect(sheet.pivot_tables().length(), content="1")

  sheet.add_image("A1", [1], ".png", "image/png")
  inspect(sheet.get_pictures("A1").length(), content="1")

  let dot_extension : Result[Unit, Error] = Ok(
    sheet.add_image("A1", [1], ".", "image/png"),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    dot_extension,
    content=(
      #|Err(UnsupportedFeature(msg="image extension missing"))
    ),
  )
  let empty_extension : Result[Unit, Error] = Ok(
    sheet.add_image("A1", [1], "", "image/png"),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    empty_extension,
    content=(
      #|Err(UnsupportedFeature(msg="image extension missing"))
    ),
  )
  let invalid_scale : Result[Unit, Error] = Ok(
    sheet.add_image("A1", [1], ".png", "image/png", scale_x=0.0),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    invalid_scale,
    content=(
      #|Err(InvalidSheetOperation(msg="picture scale must be > 0"))
    ),
  )

  let missing_width : Result[Unit, Error] = Ok(
    sheet.add_header_footer_image(
      HeaderFooterImageOptions::new(Left, [1], ".png", width="", height="8pt"),
    ),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    missing_width,
    content=(
      #|Err(InvalidHeaderFooter(msg="header/footer width empty"))
    ),
  )
  let missing_height : Result[Unit, Error] = Ok(
    sheet.add_header_footer_image(
      HeaderFooterImageOptions::new(Left, [1], ".png", width="9pt", height=""),
    ),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    missing_height,
    content=(
      #|Err(InvalidHeaderFooter(msg="header/footer height empty"))
    ),
  )
}

///|
test "worksheet wb: add_picture_from_bytes_with_options default branches" {
  let sheet = Worksheet::new("Sheet1")
  sheet.add_picture_from_bytes_with_options(
    "B2",
    [1, 2, 3],
    ".png",
    GraphicOptions::new(),
  )
  let pictures = sheet.get_pictures("B2")
  inspect(pictures.length(), content="1")
  let image = pictures[0]
  inspect(image.offset_x, content="0")
  inspect(image.offset_y, content="0")
  inspect(image.scale_x == 1.0, content="true")
  inspect(image.scale_y == 1.0, content="true")
  inspect(image.hyperlink == "", content="true")
  debug_inspect(image.hyperlink_type, content="Unset")
  inspect(image.name == "", content="true")
  inspect(image.alt_text == "", content="true")
  inspect(image.lock_aspect_ratio, content="false")
  inspect(image.print_object, content="true")
  inspect(image.locked, content="true")
  debug_inspect(image.positioning, content="OneCell")
}

///|
test "worksheet wb: picture option Some branches and guard errors" {
  let sheet = Worksheet::new("Sheet1")
  let opts = GraphicOptions::with_values(
    auto_fit=true,
    auto_fit_ignore_aspect=true,
  )
  sheet.add_picture_from_bytes_with_options("C3", [1, 2, 3], ".png", opts)
  inspect(sheet.get_pictures("C3").length(), content="1")

  let empty_vml : Result[Unit, Error] = Ok(sheet.add_vml_drawing_hf_xml("")) catch {
    e => Err(e)
  }
  debug_inspect(
    empty_vml,
    content=(
      #|Err(InvalidVmlDrawing(msg="vml drawing hf xml empty"))
    ),
  )
  let empty_options : Result[Unit, Error] = Ok(
    sheet.set_conditional_format("A1", []),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    empty_options,
    content=(
      #|Err(InvalidConditionalFormat(msg="options empty"))
    ),
  )
}

///|
test "worksheet wb: autofit merged anchor sums merged row/col spans" {
  let sheet = Worksheet::new("Sheet1")
  sheet.merge_cells("A1:B2")
  sheet.set_col_width(1, 10.0)
  sheet.set_col_width(2, 20.0)
  sheet.set_row_height(1, 10.0)
  sheet.set_row_height(2, 20.0)
  sheet.add_picture_from_bytes(
    "A1",
    [1, 2, 3],
    ".png",
    auto_fit=true,
    auto_fit_ignore_aspect=true,
  )
  let pictures = sheet.get_pictures("A1")
  inspect(pictures.length(), content="1")
  let image = pictures[0]
  inspect(image.width_emu, content="2286000")
  inspect(image.height_emu, content="342900")
}

///|
test "worksheet wb: autofit hits hidden/zero/outline pixel branches" {
  let hidden = Worksheet::new("Hidden")
  hidden.set_col_visible(1, false)
  hidden.set_row_visible(1, false)
  hidden.add_picture_from_bytes(
    "A1",
    [1],
    ".png",
    auto_fit=true,
    auto_fit_ignore_aspect=true,
  )
  let hidden_image = hidden.get_pictures("A1")[0]
  inspect(hidden_image.width_emu, content="0")
  inspect(hidden_image.height_emu, content="0")

  let zero = Worksheet::new("Zero")
  zero.set_col_width(1, 0.0)
  zero.set_row_height(1, 0.0)
  zero.add_picture_from_bytes(
    "A1",
    [1],
    ".png",
    auto_fit=true,
    auto_fit_ignore_aspect=true,
  )
  let zero_image = zero.get_pictures("A1")[0]
  inspect(zero_image.width_emu, content="0")
  inspect(zero_image.height_emu, content="0")

  let outline = Worksheet::new("Outline")
  outline.set_col_outline_level(1, 1)
  outline.set_row_outline_level(1, 1)
  outline.add_picture_from_bytes(
    "A1",
    [1],
    ".png",
    auto_fit=true,
    auto_fit_ignore_aspect=true,
  )
  let outline_image = outline.get_pictures("A1")[0]
  inspect(outline_image.width_emu, content="609600")
  inspect(outline_image.height_emu, content="171450")
}

///|
test "worksheet wb: chart option guards and reference helper copies" {
  let sheet = Worksheet::new("Sheet1")
  sheet.add_picture_from_bytes("A1", [1], ".png")

  let opts = ChartOptions::new(Col)
  opts.series.push(ChartSeries::new("Sheet1!$A$1:$A$2", "Sheet1!$B$1:$B$2"))
  opts.format = GraphicOptions::with_values(scale_x=1.25, scale_y=0.75)
  sheet.add_chart_with_options("B2", opts)
  inspect(sheet.charts().length(), content="1")

  let shifted_image = image_with_reference(sheet.get_pictures("A1")[0], "D5")
  inspect(shifted_image.reference, content="D5")
  let shifted_chart = chart_with_reference(sheet.charts()[0], "E6")
  inspect(shifted_chart.reference, content="E6")

  let bad_offset_opts = ChartOptions::new(Col)
  bad_offset_opts.format = GraphicOptions::with_values(
    offset_x=-1,
    offset_y=0,
    scale_x=1.0,
    scale_y=1.0,
  )
  let bad_offset : Result[Unit, Error] = Ok(
    sheet.add_chart_with_options("C3", bad_offset_opts),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    bad_offset,
    content=(
      #|Err(InvalidSheetOperation(msg="chart offset must be >= 0"))
    ),
  )

  let bad_scale_opts = ChartOptions::new(Col)
  bad_scale_opts.format = GraphicOptions::with_values(scale_x=0.0, scale_y=1.0)
  let bad_scale : Result[Unit, Error] = Ok(
    sheet.add_chart_with_options("C3", bad_scale_opts),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    bad_scale,
    content=(
      #|Err(InvalidSheetOperation(msg="chart scale must be > 0"))
    ),
  )
}

///|
test "worksheet wb: conditional format helper edge branches" {
  inspect(pad_left_dec(1234, 2), content="1234")
  let existing_ext = ""
  debug_inspect(
    inject_x14_id_ext_lst_into_cf_rule(existing_ext, "id1"),
    content=(
      #|""
    ),
  )
  let invalid_rule : Result[String, Error] = Ok(
    inject_x14_id_ext_lst_into_cf_rule("", "id1"),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    invalid_rule,
    content=(
      #|Err(InvalidXml(msg="cfRule tag invalid"))
    ),
  )
}

///|
test "worksheet wb: conditional/data-validation update-failure and x14 fallback paths" {
  let dv_update_fail = Worksheet::new("Sheet1")
  dv_update_fail.add_data_validation_xml(
    "\"Y\"",
  )
  let dv_update_result : Result[Unit, Error] = Ok(
    dv_update_fail.delete_data_validation(sqrefs=["A2"]),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    dv_update_result,
    content=(
      #|Err(InvalidXml(msg="data validation sqref update failed"))
    ),
  )

  let cf_merge = Worksheet::new("Sheet1")
  cf_merge.add_conditional_format_xml(
    "1=1",
  )
  cf_merge.add_conditional_format_xml(
    "2=2",
  )
  let merged = cf_merge.get_conditional_formats()
  let merged_opts = match merged.get("A1") {
    Some(value) => value
    None => fail("missing merged conditional formats")
  }
  inspect(merged_opts.length(), content="2")

  let cf_missing_tag = Worksheet::new("Sheet1")
  cf_missing_tag.add_conditional_format_xml("")
  let missing_tag_result : Result[Unit, Error] = Ok(
    cf_missing_tag.unset_conditional_format("A1"),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    missing_tag_result,
    content=(
      #|Err(InvalidXml(msg="conditionalFormatting tag missing"))
    ),
  )

  let cf_missing_sqref = Worksheet::new("Sheet1")
  cf_missing_sqref.add_conditional_format_xml(
    "1=1",
  )
  let missing_sqref_result : Result[Unit, Error] = Ok(
    cf_missing_sqref.unset_conditional_format("A1"),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    missing_sqref_result,
    content=(
      #|Err(InvalidXml(msg="conditionalFormatting sqref missing"))
    ),
  )

  let cf_update_fail = Worksheet::new("Sheet1")
  cf_update_fail.add_conditional_format_xml(
    "1=1",
  )
  let update_fail_result : Result[Unit, Error] = Ok(
    cf_update_fail.unset_conditional_format("A2"),
  ) catch {
    e => Err(e)
  }
  debug_inspect(
    update_fail_result,
    content=(
      #|Err(InvalidXml(msg="conditionalFormatting sqref update failed"))
    ),
  )

  let x14_prune = Worksheet::new("Sheet1")
  x14_prune.add_conditional_format_xml(
    "unknown1=1",
  )
  x14_prune.add_conditional_format_xml(
    "broken2=2",
  )
  x14_prune.x14_data_bars["known"] = {
    sqref: "A1",
    bar_direction: "",
    bar_solid: false,
    bar_border_color: "",
  }
  x14_prune.unset_conditional_format("C1")
  inspect(x14_prune.x14_data_bars.length(), content="0")
}

///|
test "worksheet wb: rc cell api update branches and row/col basic guards" {
  let sheet = Worksheet::new("Sheet1")
  sheet.set_cell_style_rc(2, 2, 7)
  sheet.set_cell_value_rc(2, 2, Numeric(7.0))
  sheet.set_cell_value_rc(2, 2, String("txt"))
  sheet.set_cell_formula_rc(2, 2, "1+1", value="2")
  debug_inspect(sheet.get_cell_rc(2, 2), content="Some(\"2\")")
  debug_inspect(sheet.get_cell_formula("B2"), content="Some(\"1+1\")")
  inspect(sheet.get_cell_value_raw_rc(2, 2) is Some(_), content="true")
  debug_inspect(sheet.get_cell_rc(9, 9), content="None")
  debug_inspect(sheet.get_cell_value_raw_rc(9, 9), content="None")

  let bad_get_rc : Result[String?, Error] = Ok(sheet.get_cell_rc(0, 1)) catch {
    e => Err(e)
  }
  inspect(bad_get_rc is Err(XlsxError::InvalidCellRef(_)), content="true")
  let bad_get_raw_rc : Result[CellValue?, Error] = Ok(
    sheet.get_cell_value_raw_rc(0, 1),
  ) catch {
    e => Err(e)
  }
  inspect(bad_get_raw_rc is Err(XlsxError::InvalidCellRef(_)), content="true")

  let bad_set_row : Result[Unit, Error] = Ok(sheet.set_row(0, ["A"])) catch {
    e => Err(e)
  }
  inspect(bad_set_row is Err(XlsxError::InvalidCellRef(_)), content="true")
  let bad_set_col : Result[Unit, Error] = Ok(sheet.set_col(0, ["A"])) catch {
    e => Err(e)
  }
  inspect(bad_set_col is Err(XlsxError::InvalidCellRef(_)), content="true")
  let bad_get_col : Result[Array[String], Error] = Ok(sheet.get_col(0)) catch {
    e => Err(e)
  }
  inspect(bad_get_col is Err(XlsxError::InvalidCellRef(_)), content="true")
}

///|
test "worksheet wb: row/col dimension guard and default branches" {
  let sheet = Worksheet::new("Sheet1")

  debug_inspect(sheet.get_row_height(5), content="None")
  inspect(sheet.row_visible(5), content="true")
  inspect(sheet.row_outline_level(5), content="0")
  debug_inspect(sheet.get_row_style(5), content="None")
  debug_inspect(sheet.get_col_width(5), content="None")
  inspect(sheet.col_visible(5), content="true")
  inspect(sheet.col_outline_level(5), content="0")
  debug_inspect(sheet.get_col_style(5), content="None")

  let bad_set_row_height_rc : Result[Unit, Error] = Ok(
    sheet.set_row_height(0, 1.0),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_set_row_height_rc is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )
  let bad_set_row_height_neg : Result[Unit, Error] = Ok(
    sheet.set_row_height(1, -1.0),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_set_row_height_neg is Err(XlsxError::InvalidSheetOperation(_)),
    content="true",
  )
  let bad_get_row_height : Result[Double?, Error] = Ok(sheet.get_row_height(0)) catch {
    e => Err(e)
  }
  inspect(
    bad_get_row_height is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )
  let bad_set_row_visible : Result[Unit, Error] = Ok(
    sheet.set_row_visible(0, true),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_set_row_visible is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )
  let bad_row_visible : Result[Bool, Error] = Ok(sheet.row_visible(0)) catch {
    e => Err(e)
  }
  inspect(bad_row_visible is Err(XlsxError::InvalidCellRef(_)), content="true")
  let bad_set_row_outline_row : Result[Unit, Error] = Ok(
    sheet.set_row_outline_level(0, 1),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_set_row_outline_row is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )
  let bad_set_row_outline_level : Result[Unit, Error] = Ok(
    sheet.set_row_outline_level(1, 8),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_set_row_outline_level is Err(XlsxError::InvalidSheetOperation(_)),
    content="true",
  )
  let bad_row_outline_level : Result[Int, Error] = Ok(
    sheet.row_outline_level(0),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_row_outline_level is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )
  let bad_row_style_range_bounds : Result[Unit, Error] = Ok(
    sheet.set_row_style_range(0, 1, 1),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_row_style_range_bounds is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )
  let bad_row_style_range_order : Result[Unit, Error] = Ok(
    sheet.set_row_style_range(2, 1, 1),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_row_style_range_order is Err(XlsxError::InvalidSheetOperation(_)),
    content="true",
  )
  let bad_get_row_style : Result[Int?, Error] = Ok(sheet.get_row_style(0)) catch {
    e => Err(e)
  }
  inspect(
    bad_get_row_style is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )

  let bad_set_col_width_rc : Result[Unit, Error] = Ok(
    sheet.set_col_width(0, 1.0),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_set_col_width_rc is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )
  let bad_set_col_width_neg : Result[Unit, Error] = Ok(
    sheet.set_col_width(1, -1.0),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_set_col_width_neg is Err(XlsxError::InvalidSheetOperation(_)),
    content="true",
  )
  let bad_get_col_width : Result[Double?, Error] = Ok(sheet.get_col_width(0)) catch {
    e => Err(e)
  }
  inspect(
    bad_get_col_width is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )
  let bad_set_col_visible : Result[Unit, Error] = Ok(
    sheet.set_col_visible(0, true),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_set_col_visible is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )
  let bad_col_visible : Result[Bool, Error] = Ok(sheet.col_visible(0)) catch {
    e => Err(e)
  }
  inspect(bad_col_visible is Err(XlsxError::InvalidCellRef(_)), content="true")
  let bad_set_col_outline_col : Result[Unit, Error] = Ok(
    sheet.set_col_outline_level(0, 1),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_set_col_outline_col is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )
  let bad_set_col_outline_level : Result[Unit, Error] = Ok(
    sheet.set_col_outline_level(1, 8),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_set_col_outline_level is Err(XlsxError::InvalidSheetOperation(_)),
    content="true",
  )
  let bad_col_outline_level : Result[Int, Error] = Ok(
    sheet.col_outline_level(0),
  ) catch {
    e => Err(e)
  }
  inspect(
    bad_col_outline_level is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )
  let bad_set_col_style : Result[Unit, Error] = Ok(sheet.set_col_style(0, 1)) catch {
    e => Err(e)
  }
  inspect(
    bad_set_col_style is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )
  let bad_get_col_style : Result[Int?, Error] = Ok(sheet.get_col_style(0)) catch {
    e => Err(e)
  }
  inspect(
    bad_get_col_style is Err(XlsxError::InvalidCellRef(_)),
    content="true",
  )

  sheet.set_row_style(2, 1)
  debug_inspect(sheet.get_row_style(2), content="Some(1)")
  sheet.set_row_style(2, 0)
  debug_inspect(sheet.get_row_style(2), content="None")
  sheet.set_col_style(2, 1)
  debug_inspect(sheet.get_col_style(2), content="Some(1)")
  sheet.set_col_style(2, 0)
  debug_inspect(sheet.get_col_style(2), content="None")

  let defaults = Worksheet::new("Defaults")
  defaults.set_sheet_props(
    Some(
      SheetPropsOptions::with_values(
        default_col_width=12.5,
        default_row_height=18.0,
      ),
    ),
  )
  defaults.set_col_outline_level(3, 1)
  defaults.set_row_outline_level(3, 1)
  defaults.add_picture_from_bytes(
    "C3",
    [1],
    ".png",
    auto_fit=true,
    auto_fit_ignore_aspect=true,
  )
  let image = defaults.get_pictures("C3")[0]
  inspect(image.width_emu, content="952500")
  inspect(image.height_emu, content="209550")
}

///|
test "worksheet wb: row insert/remove structural guard and adjustment branches" {
  let sheet = Worksheet::new("Sheet1")
  let bad_insert_row : Result[Unit, Error] = Ok(sheet.insert_rows(0, 1)) catch {
    e => Err(e)
  }
  inspect(bad_insert_row is Err(XlsxError::InvalidCellRef(_)), content="true")
  let bad_insert_count : Result[Unit, Error] = Ok(sheet.insert_rows(1, 0)) catch {
    e => Err(e)
  }
  inspect(
    bad_insert_count is Err(XlsxError::InvalidSheetOperation(_)),
    content="true",
  )
  let bad_remove_row : Result[Unit, Error] = Ok(sheet.remove_rows(0, 1)) catch {
    e => Err(e)
  }
  inspect(bad_remove_row is Err(XlsxError::InvalidCellRef(_)), content="true")
  let bad_remove_count : Result[Unit, Error] = Ok(sheet.remove_rows(1, 0)) catch {
    e => Err(e)
  }
  inspect(
    bad_remove_count is Err(XlsxError::InvalidSheetOperation(_)),
    content="true",
  )

  sheet.set_auto_filter("A1:B4", [])
  sheet.set_cell("A1", "head")
  sheet.set_cell("A3", "value")
  sheet.set_row_height(1, 12.0)
  sheet.add_picture_from_bytes("C3", [1], ".png")
  let chart = ChartOptions::new(Col)
  chart.series.push(ChartSeries::new("Sheet1!$A$1:$A$2", "Sheet1!$B$1:$B$2"))
  sheet.add_chart_with_options("D3", chart)
  sheet.insert_rows(2, 1)
  inspect(sheet.get_pictures("C4").length(), content="1")
  inspect(sheet.charts()[0].reference, content="D4")
  match sheet.auto_filter {
    Some(filter) => inspect(filter.range_ref, content="A1:B5")
    None => fail("missing auto filter after row insert")
  }

  sheet.remove_rows(2, 1)
  inspect(sheet.get_pictures("C3").length(), content="1")
  inspect(sheet.charts()[0].reference, content="D3")
  debug_inspect(sheet.get_row_height(1), content="Some(12)")
  match sheet.auto_filter {
    Some(filter) => inspect(filter.range_ref, content="A1:B4")
    None => fail("missing auto filter after row remove")
  }

  let drop = Worksheet::new("Drop")
  drop.merge_cells("A2:A2")
  ignore(drop.add_table("C2:D2", "DropTable", ["C", "D"]))
  drop.remove_rows(2, 1)
  inspect(drop.merged_cells().length(), content="0")
  inspect(drop.tables().length(), content="0")

  sheet.set_cell("A5", "tail")
  sheet.remove_rows(5, 1)
  debug_inspect(sheet.get_cell("A5"), content="None")
}

///|
test "worksheet wb: duplicate-row helper edge branches" {
  let (row, col, abs_col, abs_row) = parse_cell_ref_with_abs("$B$3")
  inspect(row, content="3")
  inspect(col, content="2")
  inspect(abs_col, content="true")
  inspect(abs_row, content="true")
  let bad_no_col : Result[(Int, Int, Bool, Bool), Error] = Ok(
    parse_cell_ref_with_abs("1A"),
  ) catch {
    e => Err(e)
  }
  inspect(bad_no_col is Err(XlsxError::InvalidCellRef(_)), content="true")
  let bad_invalid_char : Result[(Int, Int, Bool, Bool), Error] = Ok(
    parse_cell_ref_with_abs("A1X"),
  ) catch {
    e => Err(e)
  }
  inspect(bad_invalid_char is Err(XlsxError::InvalidCellRef(_)), content="true")
  let bad_no_row : Result[(Int, Int, Bool, Bool), Error] = Ok(
    parse_cell_ref_with_abs("A"),
  ) catch {
    e => Err(e)
  }
  inspect(bad_no_row is Err(XlsxError::InvalidCellRef(_)), content="true")
  let bad_zero_row : Result[(Int, Int, Bool, Bool), Error] = Ok(
    parse_cell_ref_with_abs("A0"),
  ) catch {
    e => Err(e)
  }
  inspect(bad_zero_row is Err(XlsxError::InvalidCellRef(_)), content="true")

  inspect(format_cell_ref_with_abs(3, 2, true, true) == "$B$3", content="true")
  let bad_format : Result[String, Error] = Ok(
    format_cell_ref_with_abs(0, 1, false, false),
  ) catch {
    e => Err(e)
  }
  inspect(bad_format is Err(XlsxError::InvalidCellRef(_)), content="true")

  let refs = duplicate_sqref_for_row(1, 2, "  A1:A1   B1:B2  ")
  debug_inspect(refs, content="[\"A2:A2\"]")

  debug_inspect(duplicate_xml_sqref("", 1, 2), content="None")
  debug_inspect(
    duplicate_xml_sqref("", 1, 2),
    content="None",
  )

  let dv = Worksheet::new("Sheet1")
  dv.add_data_validation_xml("")
  dv.duplicate_data_validations(1, 2)
  inspect(dv.data_validations().length(), content="1")

  let merge_early = Worksheet::new("MergeEarly")
  merge_early.merge_cells("A1:A3")
  merge_early.duplicate_merge_cells(1, 2)
  inspect(merge_early.merged_cells().length(), content="1")

  let merge_shift = Worksheet::new("MergeShift")
  merge_shift.merge_cells("A4:B4")
  merge_shift.duplicate_merge_cells(3, 1)
  inspect(merge_shift.merged_cells().contains("A1:B1"), content="true")

  let duplicate = Worksheet::new("Duplicate")
  duplicate.set_row(1, ["A"])
  duplicate.duplicate_row_to(1, 2)
  debug_inspect(duplicate.get_row(2), content="[\"A\"]")
  let bad_target : Result[Unit, Error] = Ok(duplicate.duplicate_row_to(1, 1)) catch {
    e => Err(e)
  }
  inspect(
    bad_target is Err(XlsxError::InvalidSheetOperation(_)),
    content="true",
  )
}

///|
test "worksheet wb: upward duplicate decodes and shifts existing sqrefs" {
  let sheet = Worksheet::new("EntitySqref")
  sheet.set_cell("A2", "tail")
  sheet.set_cell("A5", "source")
  sheet.add_data_validation_xml(
    "",
  )
  sheet.add_conditional_format_xml(
    "1=1",
  )
  sheet.duplicate_row_to(5, 2)
  debug_inspect(sheet.get_cell("A2"), content="Some(\"source\")")
  debug_inspect(sheet.get_cell("A3"), content="Some(\"tail\")")
  debug_inspect(sheet.get_cell("A6"), content="Some(\"source\")")
  inspect(sheet.data_validations().length(), content="2")
  assert_true(sheet.data_validations()[0].contains("sqref=\"A6 B6\""))
  assert_true(sheet.data_validations()[1].contains("sqref=\"A2:A2 B2:B2\""))
  inspect(sheet.conditional_formats().length(), content="2")
  assert_true(sheet.conditional_formats()[0].contains("sqref=\"A6 B6\""))
  assert_true(sheet.conditional_formats()[1].contains("sqref=\"A2:A2 B2:B2\""))
}

///|
test "worksheet wb: duplicate row remaps x14 conditional-format ids" {
  let sheet = Worksheet::new("X14Duplicate")
  let data_bar = ConditionalFormatOptions::new("data_bar")
  data_bar.set_bar_solid(true)
  data_bar.set_bar_border_color("#0000FF")
  sheet.set_conditional_format("B5:C5", [data_bar])
  let source_xml = sheet.conditional_formats()[0]
  sheet.duplicate_row_to(5, 2)
  inspect(sheet.conditional_formats().length(), content="2")
  assert_true(sheet.conditional_formats()[0].contains("sqref=\"B6:C6\""))
  assert_true(sheet.conditional_formats()[1].contains("sqref=\"B2:C2\""))
  assert_true(sheet.conditional_formats()[1] != source_xml)
  assert_eq(sheet.x14_data_bars.length(), 2)
  let mut shifted = 0
  let mut duplicated = 0
  for _, props in sheet.x14_data_bars {
    if props.sqref == "B6:C6" {
      shifted += 1
    } else if props.sqref == "B2:C2" {
      duplicated += 1
    }
  }
  assert_eq(shifted, 1)
  assert_eq(duplicated, 1)
}

///|
test "worksheet wb: row and column inserts shift sqref ranges" {
  let rows = Worksheet::new("Rows")
  rows.add_conditional_format_xml(
    "1=1",
  )
  rows.insert_rows(3, 2)
  assert_true(rows.conditional_formats()[0].contains("sqref=\"A2:B6 C7\""))

  let cols = Worksheet::new("Columns")
  cols.add_data_validation_xml(
    "",
  )
  cols.insert_cols(2, 1)
  assert_true(cols.data_validations()[0].contains("sqref=\"C2 D3:E4\""))

  let x14 = Worksheet::new("X14")
  let data_bar = ConditionalFormatOptions::new("data_bar")
  data_bar.set_bar_solid(true)
  data_bar.set_bar_border_color("#0000FF")
  x14.set_conditional_format("B2:C4", [data_bar])
  x14.insert_rows(3, 2)
  assert_eq(x14.x14_data_bars.length(), 1)
  for _, props in x14.x14_data_bars {
    assert_eq(props.sqref, "B2:C6")
  }
}

///|
test "worksheet wb: malformed sqref insertion remains atomic" {
  let sheet = Worksheet::new("Atomic")
  sheet.set_cell("A1", "source")
  sheet.set_cell("A2", "tail")
  sheet.add_data_validation_xml(
    "",
  )
  let result : Result[Unit, Error] = Ok(sheet.duplicate_row_to(1, 2)) catch {
    error => Err(error)
  }
  assert_true(result is Err(_))
  debug_inspect(sheet.get_cell("A1"), content="Some(\"source\")")
  debug_inspect(sheet.get_cell("A2"), content="Some(\"tail\")")
  debug_inspect(sheet.get_cell("A3"), content="None")
  inspect(sheet.data_validations().length(), content="1")
}

///|
test "worksheet wb: col insert/remove structural edge branches" {
  let guard_sheet = Worksheet::new("Guard")
  let bad_insert_col : Result[Unit, Error] = Ok(guard_sheet.insert_cols(0, 1)) catch {
    e => Err(e)
  }
  inspect(bad_insert_col is Err(XlsxError::InvalidCellRef(_)), content="true")
  let bad_insert_count : Result[Unit, Error] = Ok(guard_sheet.insert_cols(1, 0)) catch {
    e => Err(e)
  }
  inspect(
    bad_insert_count is Err(XlsxError::InvalidSheetOperation(_)),
    content="true",
  )
  let bad_remove_col : Result[Unit, Error] = Ok(guard_sheet.remove_cols(0, 1)) catch {
    e => Err(e)
  }
  inspect(bad_remove_col is Err(XlsxError::InvalidCellRef(_)), content="true")
  let bad_remove_count : Result[Unit, Error] = Ok(guard_sheet.remove_cols(1, 0)) catch {
    e => Err(e)
  }
  inspect(
    bad_remove_count is Err(XlsxError::InvalidSheetOperation(_)),
    content="true",
  )

  let insert = Worksheet::new("Insert")
  insert.auto_filter = Some({
    range_ref: "A1:D4",
    columns: [
      { col: 1, filters: Some(["keep"]), custom_filters: None },
      { col: 3, filters: Some(["shift"]), custom_filters: None },
    ],
  })
  insert.hyperlinks.push({
    reference: "A1:C1",
    target: "https://example.com",
    link_type: External,
    location: None,
    display: None,
    tooltip: None,
  })
  insert.add_picture_from_bytes("C3", [1], ".png")
  let insert_chart = ChartOptions::new(Col)
  insert_chart.series.push(
    ChartSeries::new("Insert!$A$1:$A$2", "Insert!$B$1:$B$2"),
  )
  insert.add_chart_with_options("D3", insert_chart)
  insert.insert_cols(2, 1)
  inspect(insert.get_pictures("D3").length(), content="1")
  inspect(insert.charts()[0].reference, content="E3")
  inspect(insert.hyperlinks()[0].reference, content="A1:D1")
  match insert.auto_filter {
    Some(filter) => {
      inspect(filter.range_ref, content="A1:E4")
      inspect(filter.columns.length(), content="2")
      inspect(filter.columns[0].col, content="1")
      inspect(filter.columns[1].col, content="4")
    }
    None => fail("missing auto filter after col insert")
  }

  let remove = Worksheet::new("Remove")
  remove.set_col_width(1, 9.0)
  remove.set_col_width(4, 11.0)
  remove.merge_cells("B1:B1")
  remove.hyperlinks.push({
    reference: "B1",
    target: "https://drop.example",
    link_type: External,
    location: None,
    display: None,
    tooltip: None,
  })
  remove.hyperlinks.push({
    reference: "A1:C1",
    target: "https://range.example",
    link_type: External,
    location: None,
    display: None,
    tooltip: None,
  })
  remove.auto_filter = Some({
    range_ref: "A1:D4",
    columns: [
      { col: 1, filters: Some(["left"]), custom_filters: None },
      { col: 2, filters: Some(["drop"]), custom_filters: None },
      { col: 4, filters: Some(["right"]), custom_filters: None },
    ],
  })
  ignore(remove.add_table("B1:B2", "DropColTable", ["B"]))
  ignore(remove.add_table("D1:E2", "KeepColTable", ["D", "E"]))
  remove.add_sparkline_group(["B1", "D1"], ["B1:B1", "D1:D1"])
  remove.add_picture_from_bytes("A1", [1], ".png")
  remove.add_picture_from_bytes("B1", [1], ".png")
  let remove_chart_a = ChartOptions::new(Col)
  remove_chart_a.series.push(
    ChartSeries::new("Remove!$A$1:$A$2", "Remove!$B$1:$B$2"),
  )
  remove.add_chart_with_options("A1", remove_chart_a)
  let remove_chart_b = ChartOptions::new(Col)
  remove_chart_b.series.push(
    ChartSeries::new("Remove!$A$1:$A$2", "Remove!$B$1:$B$2"),
  )
  remove.add_chart_with_options("B1", remove_chart_b)
  remove.col_breaks.push({ id: 0, min: 0, max: 16383, manual: true })
  remove.col_breaks.push({ id: 4, min: 0, max: 16383, manual: true })
  remove.remove_cols(2, 1)
  inspect(remove.merged_cells().length(), content="0")
  inspect(remove.hyperlinks().length(), content="1")
  inspect(remove.hyperlinks()[0].reference, content="A1:B1")
  match remove.auto_filter {
    Some(filter) => {
      inspect(filter.range_ref, content="A1:C4")
      inspect(filter.columns.length(), content="2")
      inspect(filter.columns[0].col, content="1")
      inspect(filter.columns[1].col, content="3")
    }
    None => fail("missing auto filter after col remove")
  }
  inspect(remove.tables().length(), content="1")
  inspect(remove.tables()[0].name, content="KeepColTable")
  inspect(remove.tables()[0].range_ref, content="C1:D2")
  inspect(remove.sparkline_groups().length(), content="1")
  inspect(remove.sparkline_groups()[0].sparklines.length(), content="1")
  inspect(remove.sparkline_groups()[0].sparklines[0].location, content="C1")
  inspect(remove.get_pictures("A1").length(), content="1")
  inspect(remove.get_pictures("B1").length(), content="0")
  inspect(remove.charts().length(), content="1")
  inspect(remove.charts()[0].reference, content="A1")
  debug_inspect(remove.get_col_width(1), content="Some(9)")
  debug_inspect(remove.get_col_width(3), content="Some(11)")
  inspect(remove.col_breaks.length(), content="2")
  inspect(remove.col_breaks[0].id, content="0")
  inspect(remove.col_breaks[1].id, content="3")

  let filter_drop = Worksheet::new("FilterDrop")
  filter_drop.auto_filter = Some({
    range_ref: "B1:B2",
    columns: [{ col: 2, filters: Some(["x"]), custom_filters: None }],
  })
  filter_drop.remove_cols(2, 1)
  debug_inspect(filter_drop.auto_filter, content="None")

  let alias_sheet = Worksheet::new("Alias")
  alias_sheet.set_cell("A1", "a")
  alias_sheet.set_cell("B1", "b")
  alias_sheet.set_cell("C1", "c")
  alias_sheet.remove_cols(2, 1)
  debug_inspect(alias_sheet.get_cell("A1"), content="Some(\"a\")")
  debug_inspect(alias_sheet.get_cell("B1"), content="Some(\"c\")")
  debug_inspect(alias_sheet.get_cell("C1"), content="None")
}

///|
test "worksheet wb: row remove residual drop and range-helper branches" {
  let sheet = Worksheet::new("RowDrop")
  sheet.auto_filter = Some({ range_ref: "A2:B2", columns: [] })
  sheet.hyperlinks.push({
    reference: "A1:A3",
    target: "https://rows.example",
    link_type: External,
    location: None,
    display: None,
    tooltip: None,
  })
  sheet.add_sparkline_group(["A2", "A4"], ["A2:A2", "A4:A4"])
  sheet.add_picture_from_bytes("A1", [1], ".png")
  sheet.add_picture_from_bytes("A2", [1], ".png")
  let keep_chart = ChartOptions::new(Col)
  keep_chart.series.push(
    ChartSeries::new("RowDrop!$A$1:$A$2", "RowDrop!$B$1:$B$2"),
  )
  sheet.add_chart_with_options("A1", keep_chart)
  let drop_chart = ChartOptions::new(Col)
  drop_chart.series.push(
    ChartSeries::new("RowDrop!$A$1:$A$2", "RowDrop!$B$1:$B$2"),
  )
  sheet.add_chart_with_options("A2", drop_chart)

  sheet.insert_rows(2, 1)
  inspect(sheet.hyperlinks()[0].reference, content="A1:A4")
  sheet.remove_rows(2, 1)
  inspect(sheet.hyperlinks()[0].reference, content="A1:A3")

  sheet.remove_rows(2, 1)
  debug_inspect(sheet.auto_filter, content="None")
  inspect(sheet.hyperlinks()[0].reference, content="A1:A2")
  inspect(sheet.get_pictures("A1").length(), content="1")
  inspect(sheet.get_pictures("A2").length(), content="0")
  inspect(sheet.charts().length(), content="1")
  inspect(sheet.charts()[0].reference, content="A1")
  inspect(sheet.sparkline_groups().length(), content="1")
  inspect(sheet.sparkline_groups()[0].sparklines.length(), content="1")
  inspect(sheet.sparkline_groups()[0].sparklines[0].location, content="A3")
}