#!/usr/bin/env bash

set -euo pipefail

pituitary_bin="${PITUITARY_BIN:-pituitary}"
pituitary_config="${PITUITARY_CONFIG:?PITUITARY_CONFIG is required}"
github_output_path="${GITHUB_OUTPUT:?GITHUB_OUTPUT is required}"
changed_files_json="${CHANGED_FILES_JSON:-[]}"
fail_on="${FAIL_ON:-error}"

case "$fail_on" in
  error|warning|none) ;;
  *)
    echo "invalid FAIL_ON value: $fail_on" >&2
    exit 2
    ;;
esac

workdir="$(mktemp -d)"
cleanup() {
  rm -rf "$workdir"
}
trap cleanup EXIT

changed_files_path="$workdir/changed-files.txt"
review_targets_path="$workdir/review-targets.txt"
comment_path="$workdir/comment.md"
summary_rows_path="$workdir/summary-rows.txt"
details_path="$workdir/details.md"
reviewed_bundles_json_path="$workdir/reviewed-bundles.json"

printf '%s' "$changed_files_json" | jq -r '.[]?' > "$changed_files_path"
: > "$review_targets_path"
: > "$summary_rows_path"
: > "$details_path"
printf '[]\n' > "$reviewed_bundles_json_path"

while IFS= read -r changed_file; do
  [ -n "$changed_file" ] || continue

  path_to_explain="$changed_file"
  if [ ! -e "$path_to_explain" ]; then
    candidate="$path_to_explain"
    while :; do
      parent="$(dirname "$candidate")"
      if [ "$parent" = "$candidate" ]; then
        path_to_explain=""
        break
      fi
      if [ -f "$parent/spec.toml" ]; then
        path_to_explain="$parent/spec.toml"
        break
      fi
      candidate="$parent"
    done
    [ -n "$path_to_explain" ] || continue
  fi

  explain_json="$workdir/explain.json"
  if ! "$pituitary_bin" explain-file "$path_to_explain" --config "$pituitary_config" --format json > "$explain_json" 2>/dev/null; then
    continue
  fi

  jq -r '
    .result.sources[]? |
    select(.kind == "spec_bundle") |
    select(.bundle_path != null and .bundle_path != "") |
    select(.reason == "indexed_spec_bundle" or .reason == "bundle_member_not_indexed_directly") |
    .bundle_path
  ' "$explain_json" >> "$review_targets_path"
done < "$changed_files_path"

if [ -s "$review_targets_path" ]; then
  sort -u "$review_targets_path" | sed '/^$/d' > "$review_targets_path.sorted"
  mv "$review_targets_path.sorted" "$review_targets_path"
fi

reviewed_spec_count=0
error_count=0
warning_count=0
highest_severity="none"
highest_rank=0

severity_rank() {
  case "$1" in
    none) printf '0' ;;
    info) printf '1' ;;
    warning) printf '2' ;;
    error) printf '3' ;;
    *) printf '0' ;;
  esac
}

fail_rank() {
  case "$fail_on" in
    none) printf '99' ;;
    warning) printf '2' ;;
    error) printf '3' ;;
  esac
}

while IFS= read -r bundle_path; do
  [ -n "$bundle_path" ] || continue

  reviewed_spec_count=$((reviewed_spec_count + 1))
  review_json="$workdir/review-${reviewed_spec_count}.json"
  review_markdown="$workdir/review-${reviewed_spec_count}.md"

  "$pituitary_bin" review-spec --path "$bundle_path" --config "$pituitary_config" --format json > "$review_json"
  "$pituitary_bin" review-spec --path "$bundle_path" --config "$pituitary_config" --format markdown > "$review_markdown"

  spec_ref="$(jq -r '.result.spec_ref' "$review_json")"
  drift_item_count="$(jq '[.result.doc_drift.drift_items[]?] | length' "$review_json")"
  drift_finding_count="$(jq '[.result.doc_drift.drift_items[]?.findings[]?] | length' "$review_json")"
  possible_drift_count="$(jq '[.result.doc_drift.assessments[]? | select(.status == "possible_drift")] | length' "$review_json")"
  review_warning_count="$(jq '[.warnings[]?] | length' "$review_json")"

  severity="info"
  notes="review completed"
  if [ "$drift_item_count" -gt 0 ]; then
    severity="error"
    error_count=$((error_count + 1))
    notes="${drift_finding_count} deterministic drift finding(s) across ${drift_item_count} affected doc(s)"
  elif [ "$possible_drift_count" -gt 0 ] || [ "$review_warning_count" -gt 0 ]; then
    severity="warning"
    warning_count=$((warning_count + 1))
    notes="${possible_drift_count} possible drift assessment(s), ${review_warning_count} warning(s)"
  fi

  severity_value="$(severity_rank "$severity")"
  if [ "$severity_value" -gt "$highest_rank" ]; then
    highest_rank="$severity_value"
    highest_severity="$severity"
  fi

  jq -c --arg bundle "$bundle_path" '. += [$bundle]' "$reviewed_bundles_json_path" > "$reviewed_bundles_json_path.tmp"
  mv "$reviewed_bundles_json_path.tmp" "$reviewed_bundles_json_path"

  printf '| `%s` | `%s` | **%s** | %s |\n' "$bundle_path" "$spec_ref" "$severity" "$notes" >> "$summary_rows_path"

  {
    printf '<details>\n'
    printf '<summary><code>%s</code> · <code>%s</code> · %s</summary>\n\n' "$bundle_path" "$spec_ref" "$severity"
    cat "$review_markdown"
    printf '\n</details>\n\n'
  } >> "$details_path"
done < "$review_targets_path"

has_reviews="false"
comment_body=""
if [ "$reviewed_spec_count" -gt 0 ]; then
  has_reviews="true"
  {
    echo '<!-- pituitary-review-spec -->'
    echo '## Pituitary review-spec report'
    echo
    printf 'Reviewed **%d** changed spec bundle(s) with highest severity **%s**.\n' "$reviewed_spec_count" "$highest_severity"
    echo
    echo '| Bundle | Spec Ref | Severity | Notes |'
    echo '| --- | --- | --- | --- |'
    cat "$summary_rows_path"
    echo
    cat "$details_path"
    echo '---'
    echo '_Generated by [Pituitary](https://github.com/dusk-network/pituitary) via `review-spec`._'
  } > "$comment_path"
  comment_body="$(cat "$comment_path")"
fi

exit_code=0
if [ "$highest_rank" -ge "$(fail_rank)" ]; then
  exit_code=1
fi

comment_delimiter="COMMENT_EOF_${RANDOM}_${RANDOM}"
{
  echo "reviewed-spec-count=$reviewed_spec_count"
  echo "error-count=$error_count"
  echo "warning-count=$warning_count"
  echo "highest-severity=$highest_severity"
  echo "has-reviews=$has_reviews"
  echo "reviewed-bundles=$(cat "$reviewed_bundles_json_path")"
  echo "exit-code=$exit_code"
  echo "comment-body<<$comment_delimiter"
  printf '%s\n' "$comment_body"
  echo "$comment_delimiter"
} >> "$github_output_path"
