// Sizes used across the template.
#let script-size = 9pt
#let footnote-size = 10pt
#let small-size = 11pt
#let normal-size = 12pt
#let large-size = 14pt

// #let heading-factor = 1.41
#let heading-factor = 1.33

#let heading-level-size(level) = normal-size * calc.pow(heading-factor, 4 - level)

// #let fact-counter = counter("fact")

#let chapter-counter = counter("chapter")
#let section-counter = counter("section")

// This function gets your whole document as its `body` and formats
// it as an article in the style of the American Mathematical Society.
#let ams-article(
  // The article's title.
  title: [Paper title],
  page-title: [Paper title],
  // An array of authors. For each author you can specify a name,
  // department, organization, location, and email. Everything but
  // but the name is optional.
  authors: (),
  // Your article's abstract. Can be omitted if you don't have one.
  abstract: none,
  // The article's paper size. Also affects the margins.
  paper-size: "us-letter",
  // The result of a call to the `bibliography` function or `none`.
  bibliography: none,
  // The document's content.
  body,
) = {
  // Formats the author's names in a list with commas and a
  // final "and".
  let names = authors.map(author => author.name)
  let author-string = if authors.len() == 2 {
    names.join(" and ")
  } else {
    names.join(", ", last: ", and ")
  }

  // Set document metadata.
  set document(title: title, author: names)

  // Configure the page.
  set page(
    paper: paper-size,
    // The margins depend on the paper size.
    margin: (
      // left: 3cm,
      // right: 6cm,
      inside: 4cm,
      outside: 4cm,
      x: 4cm,
      y: 4cm,
      // top: 4.5cm,
      // bottom: 3.5cm,
    ),

    header-ascent: 1cm,
    header: context {
      let i = counter(page).get().first()
      if i == 1 { return }
      set text(size: script-size)
      align(center, upper(page-title))
    },

    footer-descent: 1cm,
    footer: context {
      let i = counter(page).get().first()
      align(
        center,
        [#i],
      )
    },
  )

  // Configure headings.
  set heading(numbering: "1.")
  show heading: it => {
    // Create the heading numbering.
    let number = if it.numbering != none {
      counter(heading).display(it.numbering)
      h(7pt, weak: true)
    }

    let heading-size = heading-level-size(it.level)

    set text(
      size: heading-size,
      fill: luma(10%),
      weight: 600,
      top-edge: "bounds",
      bottom-edge: "baseline",
    )
    set par(
      spacing: 0pt,
      hanging-indent: 0pt,
      first-line-indent: 0pt,
    )


    if it.level == 1 {
      if counter(heading).get() != (0,) {
        pagebreak()
      }

      stack(
        dir: ttb,
        ..(
          if counter(heading).get() != (0,) {
            (
              layout(size => v(size.height * 25%)),
              {
                set text(size: heading-level-size(3))
                [Capitolo ]
                set text(size: heading-level-size(2))
                counter(heading).display("1")
              },
              v(heading-size * 0.61),
            )
          }
        ),
        line(length: 100%),
        v(heading-size * 0.61),
        align(right, it.body),
        v(heading-size * 0.61),
        line(length: 100%),
      )
    } else {
      block({
        number
        it.body
      })
    }

    v(heading-size, weak: true)
  }

  // Configure paragraph properties.
  set par(spacing: 1.5em, leading: 0.75em, justify: true)

  // Custom Theme Settings

  // * Inter + Fira Math
  // set text(font: "Fira Sans", weight: 400)
  set strong(delta: 200)
  // show math.equation: set text(font: "Fira Math")
  // * EB Garamond + Asana Math

  set text(font: "EB Garamond", size: normal-size)
  // show math.equation: set text(font: "Stix Two Math")
  show raw: set text(font: "Iosevka")

  // Configure lists
  set list(spacing: 1.5em, indent: 0.5em, body-indent: 0.5em, marker: [•])
  set enum(spacing: 1.5em, indent: 0.5em, body-indent: 0.5em, numbering: "i.1.a)")

  // Configure links
  // let link-color = color.mix((blue, 50%), (black, 50%))
  // show link: set text(link-color)
  // show link: it => underline(offset: 1pt, stroke: link-color, it)

  // Configure equations.
  show math.equation: set block(below: normal-size * 1.5, above: normal-size * 1.5)
  show math.equation: set text(weight: 400)

  set math.equation(
    numbering: "(1)",
    supplement: none,
  )

  show math.equation: it => {
    if it.block and not it.has("label") [
      #counter(math.equation).update(v => v - 1)
      #math.equation(it.body, block: true, numbering: none)#label("")
    ] else {
      it
    }
  }

  show ref: it => {
    if it.element != none and it.element.func() == math.equation {
      link(it.target)[Eq.~(#it)]
    } else {
      it
    }
  }

  show raw.where(block: false): it => {
    set text(size: 7.25pt, fill: luma(7%))

    box(
      outset: (x: 2pt, y: 3pt),
      fill: luma(92%),
      radius: 3pt,
      it,
    )
  }

  show raw.where(block: true): it => block(
    outset: (x: 2pt, y: 3pt),
    fill: luma(92%),
    radius: 4pt,
    inset: 4pt,
    it,
  )

  set std.bibliography(
    style: "ieee",
    title: none,
  )

  set figure(gap: 17pt)
  show figure: set block(above: 1.5em, below: 1.5em)
  show figure: it => {
    // Customize the figure's caption.
    show figure.caption: caption => {
      set text(size: small-size)
      smallcaps(caption.supplement)
      if caption.numbering != none {
        [ ]
        numbering(caption.numbering, ..caption.counter.at(it.location()))
      }
      [. ]
      caption.body
    }

    // We want a bit of space around tables and images.
    show selector.or(table, image): pad.with(x: 23pt)

    // Display the figure's body and caption.
    it
  }

  // show figure.where(kind: "fact"): it => grid(
  //   rows: 2,
  //   align: left,
  //   block(
  //     fill: red.mix((yellow, 33%)).desaturate(20%),
  //     inset: 0.5em,
  //     {
  //       set text(size: 9pt)
  //       [*Work in Progress*]
  //     },
  //   ),
  //   block(
  //     width: 100%,
  //     fill: red.mix((yellow, 33%)).desaturate(40%),
  //     inset: (x: 0.25em, y: 0.5em),
  //     it,
  //   ),
  // )

  show figure.where(kind: "definition"): it => {
    set align(start)

    block({
      strong({
        it.supplement
        [.]
      })
      [ ]
      it.body
    })
  }

  show figure.where(kind: "fact"): it => {
    set align(start)
    block({
      strong({
        it.supplement
        [.]
      })
      it.body
    })
  }

  show figure.where(kind: "proposition"): it => {
    set align(start)
    block({
      strong({
        it.supplement
        if it.numbering != none {
          [ ]
          // current chapter and section

          [#(
              ..counter(heading).get().slice(0, 1).map(it => str(it)),
              numbering(it.numbering, ..it.counter.at(it.location())),
            ).join(".")]
        }
        [.]
      })
      [ ]
      it.body
    })
  }

  show figure.where(kind: "lemma"): it => {
    set align(start)
    block({
      strong({
        it.supplement
        if it.numbering != none {
          [ ]
          // current chapter and section

          [#(
              ..counter(heading).get().slice(0, 1).map(it => str(it)),
              numbering(it.numbering, ..it.counter.at(it.location())),
            ).join(".")]
        }
        [.]
      })
      [ ]
      it.body
    })
  }

  show figure.where(kind: "theorem"): it => {
    set align(start)
    block({
      strong({
        it.supplement
        if it.numbering != none {
          [ ]
          // current chapter and section

          [#(
              ..counter(heading).get().slice(0, 1).map(it => str(it)),
              numbering(it.numbering, ..it.counter.at(it.location())),
            ).join(".")]
        }
        [.]
      })
      [ ]
      it.body
    })
  }

  show ref: it => {
    if it.element != none {
      let el = it.element
      if el == figure {
        if el.kind == "proposition" or el.kind == "lemma" or el.kind == "theorem" {
          link(
            el.location(),
            {
              if it.supplement != auto { it.supplement } else { el.supplement }
              [ ]
              (
                ..counter(heading).at(el.location()).slice(0, 1).map(it => str(it)),
                numbering(el.numbering, ..el.counter.at(el.location())),
              ).join(".")
            },
          )
        }
      } else {
        it
      }
    } else if it.citation != none {
      it
    }
  }


  // First thesis page
  context {
    set align(center + horizon)
    set text(size: 14pt)
    set page(
      margin: 0pt,
      header: none,
      footer: none,
    )

    // show text: it => box(stroke: 1pt + red, it)
    // show grid: it => box(stroke: 1pt + red, it)

    grid(
      columns: 1,
      image("assets/unipi.svg", width: 5cm),
      v(2em),
      {
        set text(size: 18pt)
        smallcaps[Università di Pisa]
      },

      v(1em),
      {
        line(length: 5.25cm)
      },

      v(1em),
      [
        *Dipartimento di Matematica \ Corso di Laurea Triennale in Matematica*
      ],

      v(6em),
      {
        [Tesi di Laurea]
      },

      v(1em),
      {
        set text(size: 18pt)
        strong(page-title)
      },

      v(15em),
      {
        block(
          width: 12cm,
          grid(
            columns: (1fr, 1fr),
            {
              set align(left)

              [Relatore: \ *Prof. Paolo Lisca*]
            },
            {
              set align(right)

              [Candidato: \ *Antonio De Lucreziis*]
            },
          ),
        )
      },

      v(6em),
      {
        line(length: 6cm)
      },

      v(1em),
      [
        *Anno Accademico 2024/2025*
      ],
    )

    pagebreak()
  }

  // Display the title and authors.
  // v(35pt, weak: true)
  // align(
  //   center,
  //   {
  //     text(size: 18pt, weight: 600, title)
  //     v(25pt, weak: true)
  //     smallcaps({
  //       text(author-string)
  //     })
  //   },
  // )


  grid(
    rows: (auto, 1fr, 2fr),
    align: center + horizon,
    v(2em),
    {
      if abstract != none {
        pad(
          x: 2em,
          grid(
            columns: 1,
            {
              set text(size: 16pt)

              [*Abstract*]
            },

            v(1em),
            {
              set align(start)
              abstract
            },
          ),
        )
      }
    },
    {
      set text(size: 16pt)
      [*Indice*]

      v(0.25em)

      set text(size: 12pt)
      outline(title: none, depth: 2, indent: 1em)
    },
  )


  context { counter("fact").update(2) }

  // Display the article's contents.
  v(29pt, weak: true)
  body

  // Display the bibliography, if any is given.
  if bibliography != none {
    pagebreak()

    {
      // colbreak()
      show heading: it => {
        set text(size: heading-level-size(2))
        block(it.body)
      }
      heading(level: 1)[Bibliografia]
    }

    bibliography
  }
}

