#!/bin/sh
set -eu

usage() {
  cat <<'USAGE'
usage: tools/emit-site-data [--out-dir DIR]

Emit the Jerboa metadata snapshot consumed by jerboa-site.

Without --out-dir the JSON is written to stdout. With --out-dir, the
snapshot is written to DIR/jerboa-source.json.
USAGE
}

out_dir=

while [ "$#" -gt 0 ]; do
  case "$1" in
    --out-dir)
      shift
      if [ "$#" -eq 0 ]; then
        echo "emit-site-data: --out-dir requires a directory" >&2
        exit 2
      fi
      out_dir=$1
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "emit-site-data: unknown argument: $1" >&2
      usage >&2
      exit 2
      ;;
  esac
  shift
done

script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
repo_root=$(CDPATH= cd -- "$script_dir/.." && pwd)

json_escape() {
  printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'
}

json_string() {
  printf '"%s"' "$(json_escape "$1")"
}

git_value() {
  git -C "$repo_root" "$@" 2>/dev/null || printf 'unknown'
}

stdin_sha256() {
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum | awk '{print $1}'
  else
    shasum -a 256 | awk '{print $1}'
  fi
}

blob_sha256() {
  git -C "$repo_root" show "HEAD:$1" | stdin_sha256
}

blob_bytes() {
  git -C "$repo_root" cat-file -s "HEAD:$1"
}

is_dirty() {
  if ! git -C "$repo_root" diff --quiet -- .; then
    return 0
  fi
  if ! git -C "$repo_root" diff --cached --quiet -- .; then
    return 0
  fi
  return 1
}

emit_git_file_list() {
  rel_dir=$1
  pattern=$2

  first=1
  git -C "$repo_root" ls-tree -r --name-only HEAD -- "$rel_dir" | sort | while IFS= read -r rel_path; do
    rest=${rel_path#"$rel_dir/"}
    case "$rest" in
      */*) continue ;;
    esac
    base=${rel_path##*/}
    case "$base" in
      $pattern) ;;
      *) continue ;;
    esac
    if [ "$first" -eq 1 ]; then
      first=0
    else
      printf ',\n'
    fi
    printf '      {"path": '
    json_string "$rel_path"
    printf ', "sha256": '
    json_string "$(blob_sha256 "$rel_path")"
    printf ', "bytes": %s}' "$(blob_bytes "$rel_path")"
  done
}

emit_json() {
  remote=$(git_value config --get remote.origin.url)
  branch=$(git_value rev-parse --abbrev-ref HEAD)
  commit=$(git_value rev-parse HEAD)
  version=unknown
  if [ -f "$repo_root/VERSION" ]; then
    version=$(sed -n '1p' "$repo_root/VERSION")
  fi
  generated_at=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
  working_tree_dirty=false
  if is_dirty; then
    working_tree_dirty=true
  fi

  printf '{\n'
  printf '  "schema": "jerboa.site-source.v1",\n'
  printf '  "repo": {\n'
  printf '    "path": '; json_string "$repo_root"; printf ',\n'
  printf '    "remote": '; json_string "$remote"; printf ',\n'
  printf '    "branch": '; json_string "$branch"; printf ',\n'
  printf '    "commit": '; json_string "$commit"; printf ',\n'
  printf '    "version": '; json_string "$version"; printf ',\n'
  printf '    "source_tree": "HEAD",\n'
  printf '    "working_tree_dirty": %s\n' "$working_tree_dirty"
  printf '  },\n'
  printf '  "generated_at": '; json_string "$generated_at"; printf ',\n'
  printf '  "site_contract": {\n'
  printf '    "human_docs": "docs/",\n'
  printf '    "machine_data": "data/",\n'
  printf '    "examples": "examples/",\n'
  printf '    "assets": "assets/"\n'
  printf '  },\n'
  printf '  "canonical_sources": {\n'
  printf '    "docs": [\n'
  emit_git_file_list docs '*.md'
  printf '\n    ],\n'
  printf '    "data": [\n'
  emit_git_file_list data '*'
  printf '\n    ],\n'
  printf '    "examples": [\n'
  emit_git_file_list examples '*'
  printf '\n    ],\n'
  printf '    "assets": [\n'
  emit_git_file_list assets '*'
  printf '\n    ]\n'
  printf '  }\n'
  printf '}\n'
}

if [ -n "$out_dir" ]; then
  mkdir -p "$out_dir"
  emit_json > "$out_dir/jerboa-source.json"
else
  emit_json
fi
