#show heading: set text(font: "New Computer Modern")
#show link: underline

// smartypants and latex compatibility
#show "--": [#sym.dash.en]
#show "---": [#sym.dash.em]
#show "\&": [#sym.amp]

// Choose the compiled language through cli by doing
//
// $ typst compile --input lang=de cv.typ
//
#let lang = {
  if "lang" in sys.inputs and sys.inputs.lang == "de" {
    "de"
  } else {
    "en"
  }
}
#let sel_word_lang(de: "", en: "") = {
  if lang == "de" {
    de
  } else {
    en
  }
}

#let _columns_3(left_body, center_body, right_body) = {
  block[
    #box(width: 1fr)[
      #align(left)[#left_body]
    ]
    #box(width: 1fr)[
      #align(center)[#center_body]
    ]
    #box(width: 1fr)[
      #align(right)[#right_body]
    ]
  ]
}

#let header(about, columns: (1.5fr, 1fr, 1fr)) = {
  [= #about.fullname]
  let contact_fields = (
    for c in about.contact {
      if "link" in c {
        ([#c.icon ~ #link(c.link)[#c.text]],)
      } else {
        ([#c.icon ~ #c.text],)
      }
    }
  )
  grid(
    columns: columns,
    gutter: 5pt,
    ..contact_fields
  )
}

#let subdued(body) = {
  block(inset: 5%, width: 85%, text(fill: luma(150), body))
}

#let entry(item: ()) = {
  if "title" in item {
    [*#item.title.at(lang)*]
  }
  if "place" in item {
    if "title" in item {
      [, ]
    }
    [_#item.place.at(lang)_]
  }
  [#h(1fr)]
  if "date" in item {
    [ _#item.date.at(lang)_ \ ]
  }
  if "bullets" in item {
    for bullet in item.bullets {
      [- #bullet.at(lang)]
    }
  }
  if "publication" in item {
    subdued[#item.publication.at(lang) \ ]
  }
  if "abstract" in item {
    subdued[#item.abstract.at(lang) \ ]
  }
}

#let horizon_line() = {
  v(-3pt)
  line(length: 100%)
  v(-5pt)
}

#let section_header(title) = {
  [== #title]
  horizon_line()
};

#let section(title: "Section", entries: (), body) = {
  section_header(title)
  if body == none or body == [] {
    for e in entries {
      entry(item: e)
    }
  } else {
    body
  }
};

// Slightly re-styled entry with PLACE first and TITLE second
#let education_entry(item: ()) = {
  assert(
    "place" in item and "title" in item and "date" in item,
    message: "Education items require place, program and date.",
  )
  [*#item.place.at(lang)*, #item.title.at(lang) #h(1fr)]
  [ _#item.date.at(lang)_ \ ]
}

// Restyled entry with PLACE not emphasized like usual, and no date but an abstract
#let thesis_entry(item: ()) = {
  assert("title" in item and "place" in item, message: "Thesis items require type and title.")
  [*#item.title.at(lang)* #item.place.at(lang) #h(1fr)]
  [#par(item.abstract.at(lang))]
}

// skill-specific entry, changing its style for sidebar
#let skill_item(item: (), is_sidebar: false) = {
  let side_list(body) = if is_sidebar { list(body) } else { par(body) }
  for skill in item {
    side_list({
      [*#skill.name.at(lang)*]
      if is_sidebar [\ ] else [ (]
      for (i, v) in skill.items.enumerate() {
        [#v.at(lang)]
        if i < skill.items.len() - 1 {
          [, ]
        }
      }
      if not is_sidebar [)]
    })
  }
}

#let cv(contents, use_sidebar: false) = {
  set text(lang: lang)

  let date_formatting = {
    if lang == "de" {
      "[day]. [month repr:long] [year]"
    } else {
      "[month repr:long] [day], [year]"
    }
  }
  set page(
    paper: "a4",
    margin: (x: 0.9cm, y: 1.3cm),
    footer: [
      #set text(
        fill: luma(200),
        size: 8pt,
      )
      #_columns_3[
        #smallcaps[#datetime.today().display(date_formatting)]
      ][
        #smallcaps[#contents.about.fullname]
      ][
        #context counter(page).display()
      ]
    ],
  )

  set par(justify: true)

  header(contents.about)

  let body = {
    if "summary" in contents {
      section(
        title: "",
        {
          contents.summary.at(lang)
        },
      )
    }

    if "experience" in contents {
      let title = sel_word_lang(en: "Professional Experience", de: "Berufserfahrung")
      section(title: title, entries: contents.experience)[]
    }

    if "education" in contents {
      let title = sel_word_lang(en: "Education", de: "Ausbildung")
      section(title: title, entries: contents.thesis + contents.education)[]
    }

    if not use_sidebar {
      if "volunteering" in contents {
        let title = sel_word_lang(en: "Volunteer Work", de: "Ehrenamt")
        section(title: title, entries: contents.volunteering)[]
      }

      if "skills" in contents {
        let title = sel_word_lang(en: "Qualifications", de: "Qualifikationen")
        section(
          title: title,
          {
            skill_item(item: contents.skills)
          },
        )
      }

      if "languages" in contents {
        let title = sel_word_lang(en: "Languages", de: "Sprachen")
        section(
          title: title,
          {
            skill_item(item: contents.languages)
          },
        )
      }
    }
  }

  let sidebar = {
    if "volunteering" in contents {
      let title = sel_word_lang(en: "Volunteer Work", de: "Ehrenamt")
      [== #title]
      for e in contents.volunteering {
        [
          - *#e.title.at(lang)* (#e.date.at(lang))
            #par(e.bullets.at(0).at(lang)) \
        ]
      }
    }

    if "languages" in contents {
      let title = sel_word_lang(en: "Languages", de: "Sprachen")
      [== #title]
      skill_item(item: contents.languages, is_sidebar: true)
      [\ ]
    }

    if "skills" in contents {
      let title = sel_word_lang(en: "Qualifications", de: "Kenntnisse")
      [== #title]
      skill_item(item: contents.skills, is_sidebar: true)
    }
  }

  if not use_sidebar {
    body
    return
  }
  let margin = 1pt
  grid(
    columns: (2fr, 1fr),
    block(
      outset: 0pt,
      inset: (top: 0.4 * margin, right: 0pt, rest: margin),
      stroke: none,
      width: 100%,
      {
        set block(above: 10pt)
        show heading.where(level: 1): it => style(s => {
          let h = text(size: 18pt, upper(it))
          let dim = measure(h, s)
          stack(
            dir: ltr,
            h,
            place(
              dy: 7pt,
              dx: 10pt,
              horizon + left,
              line(stroke: accent-color, length: 100% - dim.width - 10pt),
            ),
          )
        })
        body
      },
    ),
    {
      v(20pt)
      set block(inset: (left: 20 * margin, right: 20 * margin))
      show heading: it => align(right, upper(it))
      set list(marker: "")
      show list: it => {
        set par(justify: false)
        align(right, block(it))
      }
      sidebar
    },
  )
}

#cv.with(use_sidebar: false)(yaml("content.yml"))