// Таблицы – как в «Пример работы с Typst.typ» и gost: figure + table + table.header.
// ГОСТ 7.32 / чек-лист: в тексте и подписях – среднее тире «–» (U+2013), не длинное «—».
#let pz-figure-caption-separator = [#sym.space.nobreak#sym.dash.en#sym.space.nobreak]
// Разрыв длинных таблиц и подпись сверху задаёт шаблон modern-g7-32 (style.typ).

#show table: set text(hyphenate: true, lang: "ru")
#show table.cell: set block(inset: (x: 5pt, y: 3pt))

// Таблица внутри figure – по умолчанию один неразрывный block (обрезка длинных реестров).
#show figure.where(kind: table): set block(breakable: true)

#let pz-appendix-title(body) = heading(level: 1)[#body]

#let pz-sig-line(label) = box(
  width: 5.5cm,
  stroke: (bottom: 0.5pt),
  inset: (bottom: 3pt),
)[#label]

// Без heading(level: 1): в gost перед ним всегда pagebreak (add-pagebreaks).
#let pz-front-heading(body, page-break: true) = {
  if page-break {
    pagebreak(weak: true)
  }
  align(center)[
    #text(weight: "bold")[#upper(body)]
  ]
  v(0.75em)
}

// Официальная тема ВКР (приказ, титул, аннотация, ТЗ).
#let pz-thesis-topic = "Мобильное приложение для защищённого хранения пользовательских данных"
#let pz-thesis-topic-en = "Mobile application for secure storage of user data"
#let pz-thesis-subject = "мобильном приложении для защищённого хранения пользовательских данных"

// Бланк аннотации: 2×2 без рамок; левый столбец – отступ, текст во 2-м (2 ячейки).
#let pz-dept-mop = "кафедра МОП ЭВМ"
#let pz-dept-sait = "кафедра системного анализа и телекоммуникаций"

#let pz-biblio-strip(head, tail) = {
  table(
    columns: (0.82fr, 1fr),
    stroke: none,
    inset: (x: 0pt, y: 5pt),
    align: (left, left),
    [], head,
    [], tail,
  )
  v(0.65em)
}

#let pz-biblio-strip-ru(
  udk: "",
  author: "",
  title: "",
  direction: "09.03.04",
  institute: "Южный федеральный университет",
  faculty: "ИКТИБ",
  department: pz-dept-mop,
  year: 2026,
) = {
  let pages = context counter(page).final().first()
  pz-biblio-strip(
    [
      УДК #udk
      #linebreak()
      #upper(author)
      #linebreak()
      #quote[#title]
    ],
    [
      Квалификационная работа на степень
      #linebreak()
      «БАКАЛАВР» по направлению #direction
      #linebreak()
      #institute,
      #linebreak()
      #faculty, #department – #year#sym.space.nobreak г.,
      #linebreak()
      #pages#sym.space.nobreak с.
    ],
  )
}

#let pz-biblio-strip-en(
  udk: "",
  author: "",
  title: "",
  direction: "09.03.04",
  institute: "Southern Federal University",
  faculty: "ICTIS",
  department: "the Department of Mathematical Support and Application of Computers (MOP EVM)",
  year: 2026,
) = {
  let pages = context counter(page).final().first()
  pz-biblio-strip(
    [
      UDC #udk
      #linebreak()
      #upper(author)
      #linebreak()
      #quote[#title]
    ],
    [
      Qualification work for the degree of
      #linebreak()
      BACHELOR in the direction of #direction
      #linebreak()
      #institute,
      #linebreak()
      #faculty, #department – #year,
      #linebreak()
      #pages#sym.space.nobreak p.
    ],
  )
}

#let pz-column-count(columns) = if type(columns) == int {
  columns
} else if type(columns) == array {
  columns.len()
} else {
  1
}

// Строка из ..range().map(i => ([a], [b])) в body.pos() – один аргумент-массив.
#let pz-flatten-cells(cells) = cells.fold((), (acc, cell) => {
  if type(cell) == array { acc + cell } else { acc + (cell,) }
})

#let pz-table-inner(columns, header-cells, tab-num, start-page, ..rows) = {
  let col-n = pz-column-count(columns)
  let cont-cell = table.cell(
    colspan: col-n,
    stroke: none,
    inset: (x: 0pt, y: 2pt),
    align: left,
  )[
    #context {
      if start-page.get() == none {
        start-page.update(here().page())
      }
      let first-page = start-page.get()
      if first-page != none and here().page() > first-page {
        [Продолжение таблицы #tab-num]
      }
    }
  ]
  let header-row = if header-cells.len() > 0 {
    (cont-cell, ..header-cells)
  } else {
    (cont-cell,)
  }
  table(
    columns: columns,
    table.header(..header-row, repeat: true),
    ..rows,
  )
}

#let pz-table(caption, columns, ..body) = {
  let pos = body.pos()
  let has-header = pos.len() > 0 and pos.first().func() == table.header
  let header-cells = if has-header { pos.first().children } else { () }
  let tail = pz-flatten-cells(if has-header { pos.slice(1) } else { pos })
  let start-page = state("pz-table-start-page", none)
  figure(
    kind: table,
    context {
      let fig-loc = here()
      let tab-num = counter(figure.where(kind: table)).at(fig-loc).first()
      start-page.update(none)
      pz-table-inner(columns, header-cells, tab-num, start-page, ..arguments(..tail))
    },
    caption: caption,
  )
}

// Реестры unit-тестов: перенос длинных идентификаторов (camelCase, _); сетка как в примере Typst.
#let pz-test-table(caption, columns, ..body) = {
  let pos = body.pos()
  let has-header = pos.len() > 0 and pos.first().func() == table.header
  let header-cells = if has-header { pos.first().children } else { () }
  let tail = pz-flatten-cells(if has-header { pos.slice(1) } else { pos })
  let start-page = state("pz-table-start-page", none)
  figure(
    kind: table,
    {
      show table: set text(hyphenate: true, size: 9pt)
      show table.cell: set block(inset: (x: 5pt, y: 4pt))
      show table.cell: cell => {
        show regex("[a-z0-9][A-Z]"): m => {
          m.text.first() + sym.zws + m.text.last()
        }
        show regex("[_]"): it => it + sym.zws
        cell
      }
      context {
        let fig-loc = here()
        let tab-num = counter(figure.where(kind: table)).at(fig-loc).first()
        start-page.update(none)
        pz-table-inner(columns, header-cells, tab-num, start-page, ..arguments(..tail))
      }
    },
    caption: caption,
  )
}

#let pz-fig(path, caption, lbl) = [
  #figure(
    image(
      "../images/" + path,
      width: 100%,
      fit: "contain",
    ),
    caption: caption,
  )
  #label(lbl)
]
