#import "theme.typ": *

#let page-numbering-started = state("page-numbering-started", false)

#let start-body-page-numbering() = {
  page-numbering-started.update(true)
  counter(page).update(1)
}

#let report-body(
  title: none,
  author: none,
  date: none,
  paper-size: "a4",
  language: "zh",
  font-size: size-body,
  leading-ratio: leading-ratio,
  body-font: body-font,
  heading-font: heading-font,
  raw-font: mono-font,
  margin-x: body-margin-x,
  margin-y: body-margin-y,
  accent-color: color-primary,
  body-text-color: color-body-text,
  body,
) = {
  let scale = 1.25
  let caption-size = font-size * calc.pow(scale, -1)
  let lead-size = font-size * calc.pow(scale, 1)
  let heading-size = font-size * calc.pow(scale, 2)
  let line-height = font-size * leading-ratio
  let muted-color = color.mix(
    (rgb("#000000"), 5),
    (rgb("#ffffff"), 3),
    space: oklab,
  )

  set document(title: title, date: date)
  if author != none {
    set document(author: author)
  }

  set text(
    font: body-font,
    size: font-size,
    fill: body-text-color,
    lang: language,
  )
  show raw: set text(font: raw-font)

  set par(
    leading: line-height - font-size,
    spacing: line-height,
    justify: true,
  )

  set page(
    paper: paper-size,
    margin: (x: margin-x, top: margin-y, bottom: margin-y),
    header: none,
    footer: context {
      v(line-height / 2)
      if page-numbering-started.at(here()) {
        align(right, text(
          font: heading-font,
          size: caption-size,
          fill: muted-color,
          counter(page).display("1 / 1", both: true),
        ))
      }
    },
    footer-descent: line-height,
  )

  let report-heading(it, size, above, below, title-fill: rgb("#000000")) = block(
    width: 100%,
    breakable: false,
    above: above,
    below: below,
  )[
    #context {
      if it.numbering != none {
        let number = counter(heading).display(it.numbering)
        text(font: heading-font, size: size, weight: "bold")[
          #text(fill: accent-color)[#number]
          #h(0.35em)
          #text(fill: title-fill)[#it.body]
        ]
      } else {
        text(font: heading-font, size: size, weight: "bold", fill: title-fill, it.body)
      }
    }
  ]

  show heading.where(level: 1): it => {
    report-heading(it, heading-size, line-height * 2, line-height, title-fill: accent-color)
  }
  show heading.where(level: 2): it => {
    report-heading(it, lead-size, line-height * 2, line-height * 0.85)
  }
  show heading.where(level: 3): it => {
    report-heading(it, font-size, line-height, line-height * 0.75)
  }
  show heading.where(level: 4): it => {
    report-heading(it, caption-size, line-height * 0.85, line-height * 0.65)
  }

  set list(
    indent: 0pt,
    body-indent: line-height / 2,
    marker: text(font: heading-font, fill: accent-color, weight: "bold")[•],
  )
  set enum(
    indent: 0pt,
    body-indent: line-height / 2,
    numbering: (..nums) => text(
      font: heading-font,
      fill: accent-color,
      weight: "medium",
      numbering("1.a.i.", ..nums),
    ),
  )

  show quote.where(block: true): it => {
    v(line-height * 0.75, weak: true)
    block(width: 100%)[
      #block(
        width: 100%,
        inset: (left: tw(3.5)),
        stroke: (left: quote-bar-stroke + quote-bar-color),
      )[
        #text(font: body-font, fill: body-text-color, it.body)
      ]
    ]
    v(line-height * 0.75, weak: true)
  }

  show table: it => {
    if it.has("label") and it.label == <table-full-width> {
      it
    } else {
      [#table(
        columns: (1fr,) * it.columns.len(),
        ..it.children,
      )#label("table-full-width")]
    }
  }
  set table(
    stroke: none,
    inset: (x: line-height / 2, y: line-height / 2),
    fill: (x, y) => if y == 0 {
      accent-color
    } else if calc.even(y) {
      color-block-bg
    } else {
      none
    },
  )
  show table.cell.where(y: 0): it => {
    text(font: heading-font, weight: "bold", size: caption-size, fill: white, it)
  }

  show raw.where(block: true): block.with(
    inset: (x: line-height, y: line-height / 2),
    width: 100%,
    fill: color-block-bg,
    radius: code-block-radius,
  )
  show raw.where(block: true): set par(justify: false)
  show raw.where(block: false): box.with(
    inset: (x: 3pt, y: 0pt),
    outset: (y: 3pt),
    fill: color-block-bg,
    radius: code-inline-radius,
  )

  show link: it => {
    if type(it.dest) != str {
      it
    } else {
      text(fill: accent-color, underline(it.body))
    }
  }

  body
}
