#!/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 '
  function is_hard_scope_boundary(line) {
    return (line ~ /^[[:space:]]*end$/ || line ~ /^[[:space:]]*conn =/ || line ~ /^[[:space:]]*(test|describe) /)
  }

  function conn_used_ahead(start_idx,    i, line) {
    for (i = start_idx; i <= total_lines; i++) {
      line = lines[i]
      if (is_hard_scope_boundary(line)) return 0
      if (line ~ /conn/) return 1
    }
    return 0
  }

  # Read all lines into array
  { lines[NR] = $0 }

  END {
    total_lines = NR
    triggered = 0
    renaming = 0
    blank_lines = ""

    for (idx = 1; idx <= total_lines; idx++) {
      line = lines[idx]

      # If in renaming mode (Case 4 continuation)
      if (renaming) {
        if (is_hard_scope_boundary(line)) {
          renaming = 0
          # Fall through: do NOT continue — let the line be processed normally below
        } else {
          gsub(/conn/, "response", line)
          print line
          continue
        }
      }

      # If waiting for next non-blank line after trigger
      if (triggered) {
        if (line ~ /^[[:space:]]*$/) {
          blank_lines = blank_lines line "\n"
          continue
        }

        next_line = line
        triggered = 0

        # Case 1: var = helper(conn, status)
        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]
          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 Case 1/2/3 matched, check if conn is used further ahead
        # If so, fall through to Case 4
        if (case1 || case2 || case3) {
          if (conn_used_ahead(idx + 1)) {
            case1 = 0; case2 = 0; case3 = 0
          }
        }

        if (case1) {
          print indent c1_var " = conn |> " verb "(" args ") |> " c1_helper "(" c1_status ")"
          if (blank_lines != "") printf "%s", blank_lines
          blank_lines = ""
          continue
        }
        if (case2) {
          print indent "assert conn |> " verb "(" args ") |> " c2_helper "(" c2_status ")" c2_tail
          if (blank_lines != "") printf "%s", blank_lines
          blank_lines = ""
          continue
        }
        if (case3) {
          print indent "assert " c3_pattern " = conn |> " verb "(" args ") |> " c3_helper "(" c3_status ")"
          if (blank_lines != "") printf "%s", blank_lines
          blank_lines = ""
          continue
        }

        # If next_line references conn at all, this is Case 4 territory
        if (next_line ~ /conn/) {
          print indent "response = conn |> " verb "(" args ")"
          if (blank_lines != "") printf "%s", blank_lines
          blank_lines = ""
          gsub(/conn/, "response", next_line)
          print next_line
          renaming = 1
          continue
        }

        # 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
        continue
      }

      # Detect trigger line: conn = VERB(conn, ARGS)
      if (line ~ /^[[:space:]]*conn = (get|post|put|patch|delete|head|options)\(conn, /) {
        trigger_line = line
        match(line, /^[[:space:]]*/)
        indent = substr(line, RSTART, RLENGTH)

        rest = line
        sub(/^[[:space:]]*conn = /, "", rest)
        paren_pos = index(rest, "(")
        verb = substr(rest, 1, paren_pos - 1)
        inner = substr(rest, paren_pos + 1)
        sub(/\)$/, "", inner)
        sub(/^conn, /, "", inner)
        args = inner

        triggered = 1
        continue
      }

      # Normal mode: pass through
      if (blank_lines != "") {
        printf "%s", blank_lines
        blank_lines = ""
      }
      print line
    }
  }
  ' "$file" > "$tmpfile"

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