#!/usr/bin/env bash
#
# cheat-on-content / prediction-immutability hook
#
# Wires PreToolUse(Edit|Write) → blocks any edit that touches the
# '## 预测' / '## Prediction' section of a file under predictions/.
#
# Allows:
#   - Writing brand-new prediction files
#   - Editing the file's metadata header (above first ##)
#   - Appending to the '## 复盘' / '## Retrospective' section
#   - Touching files outside predictions/
#
# Blocks:
#   - Any change to lines between '## 预测' (or '## Prediction') and the next H2
#
# Bypass (rare, for true formatting-only fixes):
#   CHEAT_BYPASS_IMMUTABILITY=1 — single-shot bypass; logs a warning to stderr
#
# Requirements: bash 3+, jq, diff. Mac default install has all of these.
#
# Exit codes:
#   0 = allow tool call to proceed
#   1 = block tool call (Claude Code will surface stderr to the model)

set -uo pipefail

# Single-shot bypass — opt-in, logs prominently
if [[ "${CHEAT_BYPASS_IMMUTABILITY:-0}" == "1" ]]; then
  echo "[cheat-on-content] ⚠️  IMMUTABILITY BYPASS active (CHEAT_BYPASS_IMMUTABILITY=1)" >&2
  echo "[cheat-on-content] ⚠️  This should only be used for pure markdown-formatting fixes." >&2
  echo "[cheat-on-content] ⚠️  Bypass will be visible in git history." >&2
  exit 0
fi

# Read tool call payload from stdin (Claude Code passes JSON)
input=$(cat)
if [[ -z "$input" ]]; then
  # No input — let it through (defensive default; nothing to check)
  exit 0
fi

# Extract tool name and file path
tool_name=$(printf '%s' "$input" | jq -r '.tool_name // empty' 2>/dev/null || echo "")
file_path=$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty' 2>/dev/null || echo "")

# Only intercept Edit and Write
if [[ "$tool_name" != "Edit" && "$tool_name" != "Write" ]]; then
  exit 0
fi

# Only intercept files under predictions/
if [[ -z "$file_path" ]]; then
  exit 0
fi

case "$file_path" in
  */predictions/*.md|predictions/*.md)
    : # match — continue checking
    ;;
  *)
    exit 0
    ;;
esac

# Allow Write if the file does not yet exist (creating new prediction)
if [[ "$tool_name" == "Write" && ! -f "$file_path" ]]; then
  exit 0
fi

# For Edit — extract the old_string and new_string and check whether either touches
# the prediction section.
#
# Strategy: compute the byte range of the '## 预测' (or '## Prediction') section
# in the file BEFORE the edit, then check whether the old_string lies inside that
# range. If yes — block.

if [[ "$tool_name" == "Edit" ]]; then
  old_string=$(printf '%s' "$input" | jq -r '.tool_input.old_string // empty' 2>/dev/null || echo "")
  if [[ -z "$old_string" ]]; then
    exit 0
  fi

  # Find prediction section bounds. Match '## 预测' / '## Prediction' / '## 预测 v1'
  # / '## 预测 v2' / etc. — all version-suffixed prediction headings count as prediction
  # sections and are locked together.
  #
  # Section ends at the first NON-prediction '## ' heading (typically '## 复盘').
  prediction_section=$(awk '
    /^## / {
      if ($0 ~ /^## (预测|Prediction)([^a-zA-Z]|$)/) {
        in_pred=1; print; next
      } else if (in_pred) {
        exit
      }
    }
    in_pred { print }
  ' "$file_path" 2>/dev/null || echo "")

  if [[ -z "$prediction_section" ]]; then
    # File has no prediction section — let the edit through.
    # (Could be a non-conforming prediction file or an edge case.)
    exit 0
  fi

  # Check whether old_string appears inside the prediction section.
  # We use grep -F (literal) on a temporary file because old_string may contain regex chars.
  pred_tmp=$(mktemp)
  printf '%s' "$prediction_section" > "$pred_tmp"

  if grep -qF -- "$old_string" "$pred_tmp" 2>/dev/null; then
    rm -f "$pred_tmp"
    cat >&2 <<EOF

[cheat-on-content] 🚫 BLOCKED: edit targets the '## 预测' / '## Prediction' section of:
  $file_path

This violates principle #1 of cheat-on-content: predictions are immutable.
Once written, the prediction section can never be modified — only the
'## 复盘' / '## Retrospective' section can be appended to.

What to do instead:
  • If you want to redo the prediction with new info, create a NEW file:
      ${file_path%.md}_redo.md
    The original must be preserved.
  • If you noticed a factual mistake AFTER seeing data, document it in the
    '## 复盘' section: "Correction: original probability X% should have been Y%".
  • If this is a pure markdown-formatting fix (no semantic change), you can
    bypass once with: CHEAT_BYPASS_IMMUTABILITY=1 (logs to stderr, visible in git).

See: shared-references/blind-prediction-protocol.md
EOF
    exit 1
  fi

  rm -f "$pred_tmp"
  exit 0
fi

# Write tool on an existing file — that's a full overwrite, definitely touches prediction section.
if [[ "$tool_name" == "Write" && -f "$file_path" ]]; then
  cat >&2 <<EOF

[cheat-on-content] 🚫 BLOCKED: Write would overwrite an existing prediction file:
  $file_path

Use Edit on the '## 复盘' section to append retrospective content.
Use a new '_redo.md' file path to create a redo prediction.
The original prediction file must be preserved verbatim.

See: shared-references/blind-prediction-protocol.md
EOF
  exit 1
fi

exit 0
