#!/bin/sh

set -eu

util_path="${GITHUB_ACTION_PATH:-.}/scripts/utils.sh"

# shellcheck source=scripts/utils.sh
. "${util_path}"

# USAGE: json_to_md_rows <FIELD> [JSON_FILE]
#
# JSON_FILE can be piped from stdin
json_to_md_rows() {
  jq --raw-output \
    ".$1[]"' | "| `\(.name)` | \(.size) | \(.narSize) |"' "$2" |
    numfmt --suffix=B --to=iec-i --field=4,6
}

# USAGE: json_to_md_rows <FIELD> [JSON_FILE]
#
# JSON_FILE can be piped from stdin
json_to_md_rows_and_change() {
  jq --raw-output \
    ".$1[]"' | "| `\(.name)` | \(.size) | \(.sizeChange) | \(.narSize) | \(.narSizeChange) |"' |
    numfmt --suffix=B --to=iec-i --field=4,6,8,10
}

# USAGE: has_elements <FIELD> <JSON_FILE>
has_elements() {
  if [ "${2+set}" = 'set' ]; then
    [ "$(jq ".$1 != []" "$2")" = 'true' ]
  else
    [ "$(jq ".$1 != []")" = 'true' ]
  fi
}

# USAGE: markdown_from_report <REPORT> [BASE_REPORT]
#
# If BASE_REPORT is provided, a comparison will be made
markdown_from_report() {
  cat <<-"EOF"
<!-- AUTOGENERATED by nix-flake-outputs-size action -->

## Flake output sizes

<details><summary><b>Definitions</b></summary>

- `Name`: the name of the package/configuration.
- `Size`: the closure size (size on disk/NAR size + all transitive dependencies).
- `NAR Size`: the size of the build output (package without the dependencies).
	EOF
  if [ "${2+set}" = "set" ]; then
    cat <<-"EOF"
- `[NAR] Size Change`: the amount changed compared to the main branch.

</details>
		EOF
  else
    cat <<-"EOF"
</details>
		EOF
  fi
  cat <<-"EOF"

<details><summary><b>Tips on reading this data</b></summary>

- For NixOS/Home-Manager configurations you generally care only about the `Size` (closure size/size on disk).
  - Reduce the `Size` by disabling unneeded services/default packages.
- For Packages you care about both the `Size` and the `NAR Size`.
  - Reduce the `NAR Size` by reducing the size of the build outputs, e.g. don't copy unnecessary data to the $out dir, optimize binaries for size, etc.
  - Reduce the `Size` by reducing the dependencies (e.g. `buildInputs`).
  - Don't worry too much about size, some dependencies are deduplicated, e.g. `glibc` adds ~40MiB to the `Size`, but is generally shared by ~every binary on the system, so, chances are, you are already including it from somewhere else and statically linking with e.g. `musl` is not gonna improve things.

</details>

	EOF

  if [ "${2+set}" = "set" ]; then
    compare=$(jq --slurp --from-file "${GITHUB_ACTION_PATH:-.}/compare.jq" "$1" "$2")
    if echo "$compare" | has_elements 'nixosConfigurations'; then
      cat <<-"EOF"
				## NixOS Configurations

				| Name | Size | Size Change | NAR Size | NAR Size Change |
				|------|-----:|------------:|---------:|----------------:|
			EOF
      echo "$compare" | json_to_md_rows_and_change "nixosConfigurations"
      echo
    fi
    if echo "$compare" | has_elements 'homeConfigurations'; then
      cat <<-"EOF"
				## Home Manager Configurations

				| Name | Size | Size Change | NAR Size | NAR Size Change |
				|------|-----:|------------:|---------:|----------------:|
			EOF
      echo "$compare" | json_to_md_rows_and_change "homeConfigurations"
      echo
    fi
    if echo "$compare" | has_elements 'packages'; then
      cat <<-"EOF"
				## Packages

				| Name | Size | Size Change | NAR Size | NAR Size Change |
				|------|-----:|------------:|---------:|----------------:|
			EOF
      echo "$compare" | json_to_md_rows_and_change "packages"
      echo
    fi
  else
    if has_elements 'nixosConfigurations' "$1"; then
      cat <<-"EOF"
				## NixOS Configurations

				| Name | Size | NAR Size |
				|------|-----:|---------:|
			EOF
      json_to_md_rows "nixosConfigurations" "$1"
      echo
    fi
    if has_elements 'homeConfigurations' "$1"; then
      cat <<-"EOF"
				## Home Manger Configurations

				| Name | Size | NAR Size |
				|------|-----:|---------:|
			EOF
      json_to_md_rows "homeConfigurations" "$1"
      echo
    fi
    if has_elements 'packages' "$1"; then
      cat <<-"EOF"
				## Packages

				| Name | Size | NAR Size |
				|------|-----:|---------:|
			EOF
      json_to_md_rows "packages" "$1"
      echo
    fi
  fi
}

# Test outside CI
if [ "${CI:-false}" != 'true' ]; then
  markdown_from_report "$@"
  exit 0
fi

# Protect against running before a PR is made or if it is triggered on the main branch
if [ -z "$PR_ID" ]; then
  warn "No PR created for this commit"
  exit 0
fi

log 'Generating comment body'
comment=$(markdown_from_report "$@")

group 'Comment Data'
log "$comment"
endgroup

data=$(echo '{}' | jq --arg comment "$comment" '.body=$comment')
group 'Request data'
log "$data"
endgroup

if [ -z "$COMMENT_ID" ]; then
  log 'Posting new comment'
  curl -o - -X 'POST' \
    "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/issues/$PR_ID/comments" \
    -H 'Accept: application/json' \
    -H "Authorization: token $GITHUB_TOKEN" \
    -H 'Content-Type: application/json' \
    -d "$data"
else
  log "Editing comment $COMMENT_ID"
  curl -o - -X 'PATCH' \
    "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/issues/comments/$COMMENT_ID" \
    -H 'Accept: application/json' \
    -H "Authorization: token $GITHUB_TOKEN" \
    -H 'Content-Type: application/json' \
    -d "$data"
fi
