#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<'EOF'
Usage: refactor_conn_aliasing.sh [OPTIONS] FILE...
  --dry-run    Show diff without modifying files
  --help       Show usage
EOF
}

DRY_RUN=false
FILES=()

while [[ $# -gt 0 ]]; do
  case "$1" in
    --dry-run) DRY_RUN=true; shift ;;
    --help)    usage; exit 0 ;;
    -*)        echo "Unknown option: $1" >&2; usage >&2; exit 1 ;;
    *)         FILES+=("$1"); shift ;;
  esac
done

if [[ ${#FILES[@]} -eq 0 ]]; then
  echo "Error: no files specified" >&2
  usage >&2
  exit 1
fi

for file in "${FILES[@]}"; do
  if [[ ! -f "$file" ]]; then
    echo "Warning: $file not found, skipping" >&2
    continue
  fi

  tmpfile=$(mktemp)
  trap "rm -f '$tmpfile'" EXIT

  awk '
  # Detect trigger line: conn = VERB(conn, ARGS)
  # where VERB is get/post/put/patch/delete/head/options
  /^[[:space:]]*conn = (get|post|put|patch|delete|head|options)\(conn, / {
    trigger_line = $0
    # Extract leading whitespace
    match($0, /^[[:space:]]*/)
    indent = substr($0, RSTART, RLENGTH)

    # Extract verb and args from: conn = verb(conn, args)
    rest = $0
    sub(/^[[:space:]]*conn = /, "", rest)
    # rest is now: verb(conn, args)
    paren_pos = index(rest, "(")
    verb = substr(rest, 1, paren_pos - 1)
    # args portion: everything after "conn, " up to the trailing ")"
    inner = substr(rest, paren_pos + 1)
    sub(/\)$/, "", inner)
    # inner is: conn, args
    sub(/^conn, /, "", inner)
    args = inner

    # Read the next non-blank line
    triggered = 1
    next
  }

  triggered == 1 {
    # Skip blank lines, accumulating them
    if ($0 ~ /^[[:space:]]*$/) {
      blank_lines = blank_lines $0 "\n"
      next
    }

    next_line = $0
    triggered = 0

    # Now look ahead: count how many subsequent lines (until scope boundary)
    # reference "conn" — to decide Case 4 vs Cases 1-3
    # We already have next_line. Check if next_line references conn.
    # Then peek further lines.

    # For simplicity: check if next_line matches Case 1, 2, or 3 patterns.
    # If it does, check the line AFTER that for more conn references (Case 4 override).

    # Case 1: var = helper(conn, status)
    # helpers: html_response, json_response, text_response, response, redirected_to
    case1 = 0
    if (match(next_line, /^[[:space:]]*([a-z_]+) = (html_response|json_response|text_response|response|redirected_to)\(conn, [^)]+\)$/, m1)) {
      case1 = 1
      c1_var = m1[1]
      c1_helper = m1[2]
      # Extract status from helper(conn, status)
      match(next_line, /\(conn, ([^)]+)\)/, m1s)
      c1_status = m1s[1]
    }

    # Case 2: assert helper(conn, status) with optional =~ "..."
    case2 = 0
    if (match(next_line, /^[[:space:]]*assert (html_response|json_response|text_response|response|redirected_to)\(conn, ([^)]+)\)(.*)$/, m2)) {
      case2 = 1
      c2_helper = m2[1]
      c2_status = m2[2]
      c2_tail = m2[3]
    }

    # Case 3: assert %{...} = helper(conn, status)
    case3 = 0
    if (match(next_line, /^[[:space:]]*assert (%\{[^}]*\}) = (html_response|json_response|text_response|response|redirected_to)\(conn, ([^)]+)\)$/, m3)) {
      case3 = 1
      c3_pattern = m3[1]
      c3_helper = m3[2]
      c3_status = m3[3]
    }

    # If we matched Case 1, 2, or 3, emit the merged line
    if (case1) {
      print indent c1_var " = conn |> " verb "(" args ") |> " c1_helper "(" c1_status ")"
      if (blank_lines != "") printf "%s", blank_lines
      blank_lines = ""
      next
    }
    if (case2) {
      print indent "assert conn |> " verb "(" args ") |> " c2_helper "(" c2_status ")" c2_tail
      if (blank_lines != "") printf "%s", blank_lines
      blank_lines = ""
      next
    }
    if (case3) {
      print indent "assert " c3_pattern " = conn |> " verb "(" args ") |> " c3_helper "(" c3_status ")"
      if (blank_lines != "") printf "%s", blank_lines
      blank_lines = ""
      next
    }

    # If next_line references conn at all, this is Case 4 territory
    # (multiple uses without a recognized single-merge pattern)
    if (next_line ~ /conn/) {
      # Case 4: rename to response
      print indent "response = conn |> " verb "(" args ")"
      if (blank_lines != "") printf "%s", blank_lines
      blank_lines = ""
      # Replace conn with response in next_line
      gsub(/conn/, "response", next_line)
      print next_line
      # Continue replacing conn->response in subsequent lines until scope boundary
      renaming = 1
      next
    }

    # No conn reference on next line — leave trigger unchanged (fallback)
    print trigger_line
    if (blank_lines != "") printf "%s", blank_lines
    blank_lines = ""
    print next_line
    next
  }

  # Renaming mode for Case 4: replace conn with response until scope boundary
  renaming == 1 {
    # Scope boundary: blank line, "end", reduced indentation, or new conn = assignment
    if ($0 ~ /^[[:space:]]*$/ || $0 ~ /^[[:space:]]*end$/ || $0 ~ /^[[:space:]]*conn =/) {
      renaming = 0
      print
      next
    }
    gsub(/conn/, "response")
    print
    next
  }

  # Normal mode: pass through
  {
    if (blank_lines != "") {
      printf "%s", blank_lines
      blank_lines = ""
    }
    print
  }

  BEGIN { triggered = 0; renaming = 0; blank_lines = "" }
  ' "$file" > "$tmpfile"

  if $DRY_RUN; then
    diff -u "$file" "$tmpfile" || true
  else
    mv "$tmpfile" "$file"
    echo "Refactored: $file"
  fi
done
