#!/usr/bin/env bash
# fix-plan-status.sh — reconcile stale session-state/v1 task status lines against
# git reality, per the plan file's own truth_rule ("git is ground truth for
# DONE-NESS — reconcile statuses against git, never trust a stale line").
#
# A task whose every listed `files` entry is tracked in git gets its status
# rewritten to COMMITTED and blocker cleared to null. Nothing else changes.
#
# Usage: bin/fix-plan-status.sh [--dry-run] <plan.jsonl>
set -euo pipefail

if ! command -v jq >/dev/null 2>&1; then
  echo "fix-plan-status: jq required" >&2
  exit 1
fi

DRY_RUN=0
PLAN=""
for arg in "$@"; do
  case "$arg" in
    --dry-run) DRY_RUN=1 ;;
    *) PLAN="$arg" ;;
  esac
done

[[ -n "$PLAN" && -f "$PLAN" ]] || { echo "fix-plan-status: usage: bin/fix-plan-status.sh [--dry-run] <plan.jsonl>" >&2; exit 2; }

all_files_tracked() {
  local f
  for f in "$@"; do
    git ls-files --error-unmatch "$f" >/dev/null 2>&1 || return 1
  done
  return 0
}

CHANGED=0
tmp="$(mktemp)"
while IFS= read -r line; do
  type="$(jq -r '.type // empty' <<<"$line")"
  status="$(jq -r '.status // empty' <<<"$line")"

  if [[ "$type" == "task" && ( "$status" == "PENDING" || "$status" == "BLOCKED" ) ]]; then
    mapfile -t files < <(jq -r '.files[]? // empty' <<<"$line")
    if [[ ${#files[@]} -gt 0 ]] && all_files_tracked "${files[@]}"; then
      id="$(jq -r '.id' <<<"$line")"
      echo "$PLAN: $id: $status -> COMMITTED (files already tracked in git)"
      line="$(jq -c '.status = "COMMITTED" | .blocker = null' <<<"$line")"
      CHANGED=$((CHANGED + 1))
    fi
  fi
  echo "$line" >> "$tmp"
done < "$PLAN"

if [[ "$DRY_RUN" -eq 1 ]]; then
  rm -f "$tmp"
  echo "dry-run: $CHANGED task(s) would change, no file written"
else
  mv "$tmp" "$PLAN"
  echo "fixed $CHANGED task(s) in $PLAN"
fi
