#!/bin/bash
# Copyright 2026 Marc-Antoine Ruel. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.

# Rejects malformed, overlong, or co-authored commit messages.

set -euo pipefail

print_commit_guidance() {
  printf '%s\n' \
    'Commit guidance for coding agents:' \
    '  - Use a concise subject no longer than 120 characters.' \
    '  - Separate an optional body from the subject with a blank line.' \
    '  - When useful, explain the rationale and tradeoffs; do not restate the diff.' >&2
}

if (($# != 1)); then
  printf '%s\n' 'Usage: commit-msg <message-file>' >&2
  print_commit_guidance
  exit 2
fi

message_file=$1
readonly message_file

if [[ ! -f "$message_file" ]]; then
  printf 'Commit message file does not exist: %s\n' "$message_file" >&2
  print_commit_guidance
  exit 2
fi

if grep -Fq '\n' "$message_file"; then
  printf '%s\n' 'Commit messages must use actual line breaks, not literal \n sequences.' >&2
  print_commit_guidance
  exit 1
fi

if grep -Eiq '^co-authored-by: ' "$message_file"; then
  printf '%s\n' 'Commit messages must not contain Co-authored-by trailers.' >&2
  print_commit_guidance
  exit 1
fi

if ! awk '
  /^[[:space:]]*#/ { next }
  !subject {
    if (NF) subject = 1
    next
  }
  !separator {
    if (!NF) {
      separator = 1
      next
    }
    invalid_separator = 1
    next
  }
  END { exit !subject || invalid_separator }
' "$message_file"; then
  printf '%s\n' 'Commit messages need a subject and a blank line before any body.' >&2
  print_commit_guidance
  exit 1
fi

if ! awk '
  /^[[:space:]]*#/ { next }
  NF && length($0) > 120 {
    printf "Commit message line %d is %d characters; maximum is 120.\n", NR, length($0) > "/dev/stderr"
    exit 1
  }
' "$message_file"; then
  print_commit_guidance
  exit 1
fi
