/// An *opinionated* template for a longer report or thesis.
#let tasteful-thesis(
  /// The main title of the document.
  /// -> string
  title: "",
  /// An optional subtitle for the document.
  /// -> string
  subtitle: "",
  /// The authors of the document.
  /// -> array(string)
  authors: (),
  supervisors: (),
  affiliation: none,
  other: none,
  abstract: none,

  background-image: none,
  date: datetime.today().display(),
  background-color: color.blue,
  logos: (),
  font: "New Computer Modern",
  alpha: 50%,
  pre_content: none,
  body,

) = {
  //
  // Global settings and style customization.
  //
  set document(author: authors, title: title, description: subtitle)

  // Set body font family.
  set text(font: font, 11pt)
  show heading: set text(font: font, fill: background-color)

  let font-color = color;
  // Check if the background color is closer to black or white
  let components = background-color.components()
  let luminance = float(0.299 * components.at(0) + 0.587 * components.at(1) + 0.114 * components.at(2))
  if luminance > 0.5 {
    font-color = color.black
  } else {
    font-color = color.white
  }


  // color links
  show link: it => underline(text(fill: background-color, it))
  show ref: it => text(fill: background-color, it)
  show ref.where(): it => text(fill: background-color, it)

  // colors lists
  set enum(indent: 1em, numbering: n => [#text(fill: background-color, numbering("1.", n))])
  set list(indent: 1em, marker: n => [#text(fill: background-color, "•")])


  // figure placement and caption style
  set figure(placement: top)
  show figure.caption: set text(size: 0.85em)


  // citation style
  set cite(
    form: "prose"
  )
  show cite: it => text(fill: background-color, it)

  // add space for heading
  show heading.where(level:1): it => it + v(0.5em)


  set math.equation(numbering: "(1)", supplement: [Eq.])

  //
  // Included content
  //

  // code blocks
  show raw.where(block: true) : it => h(0.5em) + box(fill: background-color.lighten(80%), outset: 0.5em, width: 100%, it) + h(0.5em)



  let authors_block(authors, denomination: "Author") = {
    if authors.len() == 0 {
      return
    }
    let prefix = denomination
    if authors.len() > 2 {
      prefix += "s"
    }

    stack(
      dir: ltr,
      text(prefix + ": ", weight: 600),
      stack(
        dir: ttb,
        spacing: 0.5em,
        ..authors
      )
    )
  }

  //
  // Title page
  //

  // Title page background
  set page(
    // the title page should not have any margin, this will be reset in the next page
    margin: 0pt,
  )
[
  #set image(
      width: 105%,
    )
  // set the image first so that it is the lowest layer
  #place(
    bottom,
    background-image
  )
]

  //  define the base widht of a tile, as a tenth of the page width
  let tile_width = 1.51cm

  // Add a tiling of white squares over the background to simulate a grid
  for i in range(0, 14) {
    for j in range(0, 14) {
      place(
        bottom + right,
        dx: -i * tile_width + 0.1em,
        dy: -j * tile_width,
      )[
        #square(
          size: tile_width,
          // fill: gradient.linear(
          //   color.white,
          //   color.black.transparentize(0%),
          //   color.black.transparentize(0%),
          //   color.black.transparentize(0%),
          //   color.black.transparentize(0%),
          //   angle: 45deg,
          // ),
          fill: none,
          stroke: (
            paint: color.white,
            thickness: 0.02em,
          )
        )
      ]
    }
  }



  place(
    top + left,
    dx: -20em,
    line(
      angle: -10deg,
      length: 200%,
      stroke: (
        paint: background-color.lighten(alpha),
        thickness: 900pt,
      ),
    ),
  )

  place(
    top + left,
    dx: -20em,
    line(
      angle: -10deg,
      length: 200%,
      stroke: (
        paint: background-color,
        thickness: 800pt,
      )
    ),
  )

  place(
    bottom + right,
    dx: 20em,
    dy: 20em,
    line(
      angle: -10deg,
      length: 200%,
      stroke: (
        paint: background-color.lighten(alpha),
        thickness: 400pt,
      )
    ),
  )

  place(
    bottom + right,
    dx: 20em,
    dy: 20em,
    line(
      angle: -10deg,
      length: 200%,
      stroke: (
        paint: background-color,
        thickness: 300pt,
      )
    ),
  )

  // add a few more tiles *above* the background image to simulate a grid structure
  let draw_pairs = (
    (0, 10),
    // (1, 10),
    // (2, 10),
    (3, 10),
    // (4, 10),
    (5, 10),
    (6, 10),
    // (7, 10),
    (8, 10),
    // (9, 10),
    (10, 10),
    (11, 10),
    // (12, 10),
    (13, 10),

    (0, 11),
    (1, 11),
    // (2, 11),
    (3, 11),
    // (4, 11),
    (5, 11),
    // (6, 11),
    // (7, 11),
    (8, 11),
    // (9, 11),
    (10, 11),
    (11, 11),
    // (12, 11),
    (13, 11),

    (0, 12),
    // (1, 12),
    // (2, 12),
    (3, 12),
    // (4, 12),
    (5, 12),
    // (6, 12),
    // (7, 12),
    // (8, 12),
    (9, 12),
    // (10, 12),
    // (11, 12),
    // (12, 12),
    // (13, 12),


    // (0, 13),
    (1, 13),
    // (2, 13),
    (3, 13),
    // (4, 13),
    // (5, 13),
    // (6, 13),
    (7, 13),
    // (8, 13),
    // (9, 13),
    // (10, 13),
    // (11, 13),
    (12, 13),
    // (13, 13),


    // (0, 14),
    // (1, 14),
    // (2, 14),
    // (3, 14),
    (4, 14),
    // (5, 14),
    // (6, 14),
    // (7, 14),
    // (8, 14),
    // (9, 14),
    (10, 14),
    // (11, 14),
    // (12, 14),
    (13, 14),
  )

  for (i, j) in draw_pairs {
    place(
      bottom + right,
      dx: -i * tile_width + 0.1em,
      dy: -j * tile_width,
    )[
      #square(
        size: tile_width,
        fill: none,
        stroke: (
          paint: color.white,
          thickness: 0.02em,
        )
      )
    ]
  }


  // Title page content
  pad(
    x: 4em,
    y: 4em,
  )[
    #set text(font: font, fill: font-color)
    #align(center, text(title, size: 2.5em, weight: 600))
    #if subtitle != none {
      v(1.5em, weak: true)
      align(center, text(subtitle, size: 2em, weight: 500))
    }
    #pad(
      x: 6em,
      y: 0em,
    )[
      #stack(
        dir: ltr,
        authors_block(authors),
        h(1fr),
        authors_block(supervisors, denomination: "Supervisor")
      )
    ]
  ]


  let padded_logos = logos.map(logo => pad(x: 0.2cm, logo))

  place(bottom + right, dy: -2em, dx: -2em)[
    #set text(font: font, fill: font-color, size: 1.2em)
    #set image(height: 0.8cm, width: auto)

    #date

    #stack(
      dir: ltr,
      // text(font: font, 1em, affiliation, fill: font-color),
      ..padded_logos
    )
  ]



  if pre_content != none {
    pagebreak()
    place(
      top + left,
      // dx: 2em,
      // dy: 2em,
    )[
      #pre_content
    ]
  }


  pagebreak()

  let footer = grid(
    rows: auto,
    v(0mm),
    line(length: 100%, stroke: (paint: background-color, thickness: 1pt)),
    v(2.5mm),
    text(
    )[
      #title
      #h(1fr)
      #context [
        #text(counter(page).display())
      ]
      // context needed for page counter for typst >= 0.11.0
    ]
  )

  set page(
    // no header
    footer: footer,
    margin: 4em,
  )
  counter(page).update(1)

  //
  // "First" page - abstract and TOC
  //

  abstract
  v(2em)
  outline()

  pagebreak()


  //
  // Main body.
  //
  set heading(numbering: "1.")
  set par(justify: true)

  body
}

