{{/*
  Hugo Blox Page Link Builder
  Build a normalized list of page links from:
  - Author-provided front matter `links` (array order respected)
  - Auto-detected resources (local PDF, cite.bib)
  - Derived identifiers from `hugoblox.ids`
  - Associated internal `projects` references

  Inputs: dict { "page": . , "is_list": 0|1 }
  Output: slice of dicts with fields: type, url, icon, labelKey, label, contexts, rel

  Deprecations handled with warnings and mapped:
    - external_link -> type: site
    - url_pdf -> type: pdf
    - url_preprint -> type: preprint
    - url_code -> type: code
    - url_dataset -> type: dataset
    - url_poster -> type: poster
    - url_project -> type: project
    - url_slides -> type: slides
    - url_source -> type: source
    - url_video -> type: video
*/}}

{{ $page := .page }}
{{ $is_list := .is_list }}

{{ $types := hugo.Data.link_types.types }}
{{ $derived := hugo.Data.link_types.derived }}

{{ $links := slice }}
{{ $seen := newScratch }}
{{ $seen.Set "set" (dict) }}

{{/* 1) Author-provided links (array order) */}}
{{ with $page.Params.links }}
  {{ range . }}
    {{/* Support new fields: type, url, icon (pack/name), label, contexts, rel; legacy: name */}}
    {{ $type := .type | default "custom" }}
    {{ $url := .url | default "" }}
    {{/* Optional provider+id derivation for common platforms */}}
    {{ if and (not $url) .id }}
      {{ if eq $type "doi" }}
        {{ $url = replace (index (index $derived "doi") "url_template") "{id}" (printf "%v" .id) }}
      {{ else if and (eq $type "preprint") (eq .provider "arxiv") }}
        {{ $url = replace (index (index $derived "arxiv") "url_template") "{id}" (printf "%v" .id) }}
      {{ else if and (eq $type "preprint") (eq .provider "openreview") }}
        {{ $url = replace (index (index $derived "openreview") "url_template") "{id}" (printf "%v" .id) }}
      {{ end }}
    {{ end }}
    {{ $typeF := $type }}
    {{ $urlF := $url }}
    {{ $keyF := printf "%s::%s" $typeF $urlF }}
    {{ if not ($seen.Get (printf "set.%s" $keyF)) }}
      {{ $seen.SetInMap "set" $keyF true }}
      {{ $links = $links | append (dict
          "type" $typeF
          "url" $urlF
          "icon" (.icon | default (index (index $types $typeF) "icon") | default "hero/link")
          "labelKey" (index (index $types $typeF) "label_i18n")
          "label" (.label | default .name)
          "contexts" (.contexts | default (slice "list" "page"))
          "rel" .rel
        ) }}
    {{ end }}
  {{ end }}
{{ end }}

{{/* 2) Associated projects (internal) */}}
{{ with $page.Params.projects }}
  {{ range . }}
    {{ with (site.GetPage (printf "project/%s" .)) }}
      {{ $typeF := "project" }}
      {{ $urlF := .RelPermalink }}
      {{ $keyF := printf "%s::%s" $typeF $urlF }}
      {{ if not ($seen.Get (printf "set.%s" $keyF)) }}
        {{ $seen.SetInMap "set" $keyF true }}
        {{ $links = $links | append (dict
            "type" $typeF
            "url" $urlF
            "icon" (index (index $types $typeF) "icon")
            "labelKey" (index (index $types $typeF) "label_i18n")
            "contexts" (slice "list" "page")
          ) }}
      {{ end }}
    {{ end }}
  {{ end }}
{{ end }}

{{/* 2b) Slides relation parameter (legacy but common) */}}
{{ with $page.Params.slides }}
  {{ if reflect.IsMap . }}
    {{/* Skip: slides map is Reveal.js config for slide decks. */}}
  {{ else if reflect.IsSlice . }}
    {{ range . }}
      {{ with (site.GetPage (printf "slides/%s" .)) }}
        {{ $typeF := "slides" }}
        {{ $urlF := .RelPermalink }}
        {{ $keyF := printf "%s::%s" $typeF $urlF }}
        {{ if not ($seen.Get (printf "set.%s" $keyF)) }}
          {{ $seen.SetInMap "set" $keyF true }}
          {{ $links = $links | append (dict
              "type" $typeF
              "url" $urlF
              "icon" (index (index $types $typeF) "icon")
              "labelKey" (index (index $types $typeF) "label_i18n")
              "contexts" (slice "list" "page")
            ) }}
        {{ end }}
      {{ else }}
        {{ warnf "`slides` relation could not resolve to a page for %s" $page.File.Path }}
      {{ end }}
    {{ end }}
  {{ else }}
    {{ with (site.GetPage (printf "slides/%s" .)) }}
      {{ $typeF := "slides" }}
      {{ $urlF := .RelPermalink }}
      {{ $keyF := printf "%s::%s" $typeF $urlF }}
      {{ if not ($seen.Get (printf "set.%s" $keyF)) }}
        {{ $seen.SetInMap "set" $keyF true }}
        {{ $links = $links | append (dict
            "type" $typeF
            "url" $urlF
            "icon" (index (index $types $typeF) "icon")
            "labelKey" (index (index $types $typeF) "label_i18n")
            "contexts" (slice "list" "page")
          ) }}
      {{ end }}
    {{ else }}
      {{ warnf "`slides` relation could not resolve to a page for %s" $page.File.Path }}
    {{ end }}
  {{ end }}
{{ end }}

{{/* 3) Auto-detected resources (local PDF by content basename, cite.bib) */}}
{{ with $page.File.ContentBaseName }}
  {{ with ($page.Resources.GetMatch (printf "%s.pdf" .)) }}
    {{ $typeF := "pdf" }}
    {{ $urlF := .RelPermalink }}
    {{ $keyF := printf "%s::%s" $typeF $urlF }}
    {{ if not ($seen.Get (printf "set.%s" $keyF)) }}
      {{ $seen.SetInMap "set" $keyF true }}
      {{ $links = $links | append (dict
          "type" $typeF
          "url" $urlF
          "icon" (index (index $types $typeF) "icon")
          "labelKey" (index (index $types $typeF) "label_i18n")
          "contexts" (slice "list" "page")
        ) }}
    {{ end }}
  {{ end }}
{{ end }}
{{ with ($page.Resources.GetMatch "cite.bib") }}
  {{ $typeF := "bibtex" }}
  {{ $urlF := .RelPermalink }}
  {{ $keyF := printf "%s::%s" $typeF $urlF }}
  {{ if not ($seen.Get (printf "set.%s" $keyF)) }}
    {{ $seen.SetInMap "set" $keyF true }}
    {{ $links = $links | append (dict
        "type" $typeF
        "url" $urlF
        "icon" (index (index $types $typeF) "icon")
        "labelKey" (index (index $types $typeF) "label_i18n")
        "contexts" (slice "list" "page")
      ) }}
  {{ end }}
{{ end }}

{{/* 4) Derived links from identifiers under `hugoblox.ids` */}}
{{ with $page.Params.hugoblox }}
  {{ with .ids }}
    {{ range $key, $val := . }}
      {{ with (index $derived $key) }}
        {{ $der := . }}
        {{ $typeF := index $der "type" }}
        {{ $urlF := replace (index $der "url_template") "{id}" (printf "%v" $val) }}
        {{ $keyF := printf "%s::%s" $typeF $urlF }}
        {{ if not ($seen.Get (printf "set.%s" $keyF)) }}
          {{ $seen.SetInMap "set" $keyF true }}
          {{ $links = $links | append (dict
              "type" $typeF
              "url" $urlF
              "icon" (index $der "icon")
              "labelKey" (index $der "label_i18n")
              "contexts" (slice "list" "page")
            ) }}
        {{ end }}
      {{ end }}
    {{ end }}
  {{ end }}
{{ end }}

{{/* 5) Legacy fields -> deprecation warnings and normalized items */}}
{{/* external_link */}}
{{ with $page.Params.external_link }}
  {{ warnf "`external_link` is deprecated. Use `links: [{type: site, url: ...}]` in %s" $page.File.Path }}
  {{ $typeF := "site" }}
  {{ $urlF := . }}
  {{ $keyF := printf "%s::%s" $typeF $urlF }}
  {{ if not ($seen.Get (printf "set.%s" $keyF)) }}
    {{ $seen.SetInMap "set" $keyF true }}
    {{ $links = $links | append (dict
        "type" $typeF
        "url" $urlF
        "icon" (index (index $types $typeF) "icon")
        "labelKey" (index (index $types $typeF) "label_i18n")
        "contexts" (slice "list" "page")
      ) }}
  {{ end }}
{{ end }}
{{/* top-level doi */}}
{{ with $page.Params.doi }}
  {{ warnf "Top-level `doi` is deprecated. Use `hugoblox.ids: { doi: ... }` in %s" $page.File.Path }}
  {{ with (index $derived "doi") }}
    {{ $der := . }}
    {{ $typeF := index $der "type" }}
    {{ $urlF := replace (index $der "url_template") "{id}" (printf "%v" $page.Params.doi) }}
    {{ $keyF := printf "%s::%s" $typeF $urlF }}
    {{ if not ($seen.Get (printf "set.%s" $keyF)) }}
      {{ $seen.SetInMap "set" $keyF true }}
      {{ $links = $links | append (dict
          "type" $typeF
          "url" $urlF
          "icon" (index $der "icon")
          "labelKey" (index $der "label_i18n")
          "contexts" (slice "list" "page")
        ) }}
    {{ end }}
  {{ else }}
    {{ $typeF := "doi" }}
    {{ $urlF := printf "https://doi.org/%v" $page.Params.doi }}
    {{ $keyF := printf "%s::%s" $typeF $urlF }}
    {{ if not ($seen.Get (printf "set.%s" $keyF)) }}
      {{ $seen.SetInMap "set" $keyF true }}
      {{ $links = $links | append (dict
          "type" $typeF
          "url" $urlF
          "icon" (index (index $types $typeF) "icon")
          "labelKey" (index (index $types $typeF) "label_i18n")
          "contexts" (slice "list" "page")
        ) }}
    {{ end }}
  {{ end }}
{{ end }}
{{/* Map of legacy url_* to new types */}}
{{ $legacy := dict
  "url_pdf" "pdf"
  "url_preprint" "preprint"
  "url_code" "code"
  "url_dataset" "dataset"
  "url_poster" "poster"
  "url_project" "project"
  "url_slides" "slides"
  "url_source" "source"
  "url_video" "video"
}}
{{ range $legacyKey, $legacyType := $legacy }}
  {{ with index $page.Params $legacyKey }}
    {{ warnf "`%s` is deprecated. Use `links: [{type: %s, url: ...}]` in %s" $legacyKey $legacyType $page.File.Path }}
    {{/* Resolve relative resource if present */}}
    {{ $u := . }}
    {{ with ($page.Resources.GetMatch $u) }}
      {{ $u = .RelPermalink }}
    {{ else }}
      {{ $u = $u | relURL }}
    {{ end }}
    {{ $typeF := $legacyType }}
    {{ $urlF := $u }}
    {{ $keyF := printf "%s::%s" $typeF $urlF }}
    {{ if not ($seen.Get (printf "set.%s" $keyF)) }}
      {{ $seen.SetInMap "set" $keyF true }}
      {{ $links = $links | append (dict
          "type" $typeF
          "url" $urlF
          "icon" (index (index $types $typeF) "icon")
          "labelKey" (index (index $types $typeF) "label_i18n")
          "contexts" (slice "list" "page")
        ) }}
    {{ end }}
  {{ end }}
{{ end }}

{{- return $links -}}
