#!/usr/bin/env bash

# --------------------------------------
# This script checks multiple branches for certain conditions.
# It is meant to be run within a git repository.
# --------------------------------------

# list of branches to check.
# "master" and "REL_13_STABLE" through "REL_17_STABLE".
BRANCHES=(
  "master"
  "REL_13_STABLE"
  "REL_14_STABLE"
  "REL_15_STABLE"
  "REL_16_STABLE"
  "REL_17_STABLE"
)

MASTER_PATCH_FILE="./copy_from_stdin_no_warning_for_master3.patch"
STABLES_PATCH_FILE="./copy_from_stdin_no_warning_for_stables.patch"

# mapping from branch to patch file path.
declare -A PATCH_FILES=(
  ["master"]="$MASTER_PATCH_FILE"
  ["REL_13_STABLE"]="$STABLES_PATCH_FILE"
  ["REL_14_STABLE"]="$STABLES_PATCH_FILE"
  ["REL_15_STABLE"]="$STABLES_PATCH_FILE"
  ["REL_16_STABLE"]="$STABLES_PATCH_FILE"
  ["REL_17_STABLE"]="$STABLES_PATCH_FILE"
)

# --------------------------------------
# other constants.
# --------------------------------------
SHOULD_BE_WARNED_PGC_SOURCE="copy_from_should_be_warned.pgc"
SHOULD_NOT_BE_WARNED_PGC_SOURCE="copy_from_ok.pgc"

# --------------------------------------
# commands for confirmation checks.
# --------------------------------------

# Confirmation 1: Two-step build commands (only check the exit code of the second one).
BUILD_CMD_1="./configure --enable-cassert --enable-tap-tests --prefix=$HOME/work/postgres/local_install >/dev/null 2>&1"
BUILD_CMD_2="make -j 8 >/dev/null 2>&1 && make install >/dev/null 2>&1"

# Confirmation 2: Regression test command.
REGRESSION_TEST_CMD="make check >/dev/null 2>&1"

# Confirmation 3: The command line whose output must match a hard-coded string.
CMD_LINE_1="./local_install/bin/ecpg $SHOULD_BE_WARNED_PGC_SOURCE"
EXPECTED_OUTPUT_FOR_CMD_LINE_1=" COPY FROM STDIN is not implemented"

# Confirmation 4: The command line which should produce no output at all.
CMD_LINE_2="./local_install/bin/ecpg $SHOULD_NOT_BE_WARNED_PGC_SOURCE"

# --------------------------------------
# Function to apply patch
# --------------------------------------
apply_patch() {
  local patch_file_path="$1"
  # Apply the patch with patch -p0 < "patch_file_path"
  if [[ -f "$patch_file_path" ]]; then
    echo "Applying patch: $patch_file_path"
    patch -p1 < "$patch_file_path"
    if [[ $? -ne 0 ]]; then
      echo "Error: Failed to apply patch $patch_file_path"
      exit 1
    fi
  else
    echo "Error: Patch file not found ($patch_file_path)"
    exit 1
  fi
}

# --------------------------------------
# Main processing
# --------------------------------------

for branch in "${BRANCHES[@]}"; do
  echo "------------------------------"
  echo "Checking branch: $branch"
  echo "------------------------------"

  # 1) Checkout the branch
  # ------------------------------
  # Switch to the branch we want to check.
  git checkout "$branch" >/dev/null 2>&1
  if [[ $? -ne 0 ]]; then
    echo "Error: Failed to check out branch $branch"
    exit 1
  fi

  echo "[HEAD]"
  git log | head -n 3

  # 2) Apply the patch corresponding to this branch
  # ------------------------------
  apply_patch "${PATCH_FILES[$branch]}"

  # 3) Confirmation 1: Two-step build (check exit code of the second command)
  # ------------------------------
  echo "[Confirmation 1] Start building..."
  echo "  Running: $BUILD_CMD_1"
  eval "$BUILD_CMD_1"

  echo "  Running: $BUILD_CMD_2"
  eval "$BUILD_CMD_2"
  if [[ $? -ne 0 ]]; then
    echo "Error: Build command (second step) failed on branch $branch."
    exit 1
  fi

  # 4) Confirmation 2: Regression test command
  # ------------------------------
  echo "[Confirmation 2] Running regression tests..."
  cd src/interfaces/ecpg
  eval "$REGRESSION_TEST_CMD"
  if [[ $? -ne 0 ]]; then
    echo "Error: Regression test failed on branch $branch."
    exit 1
  fi
  cd ../../..

  # 5) Confirmation 3: check output of warning needed execution
  # ------------------------------
  echo "[Confirmation 3] Checking output for command: $CMD_LINE_1"
  OUTPUT_1="$($CMD_LINE_1 2>&1)"
  CUTED_OUTPUT_1=$(echo "${OUTPUT_1}" | cut -d':' -f4)
  if [[ "$CUTED_OUTPUT_1" != "$EXPECTED_OUTPUT_FOR_CMD_LINE_1" ]]; then
    echo "Error: Output mismatch for $CMD_LINE_1 on branch $branch."
    echo "  Expected: $EXPECTED_OUTPUT_FOR_CMD_LINE_1"
    echo "  Got:      $CUTED_OUTPUT_1"
    exit 1
  fi

  # 6) Confirmation 4: check output of no warning needed execution
  # ------------------------------
  echo "[Confirmation 4] Checking no output for command: $CMD_LINE_2"
  OUTPUT_2="$($CMD_LINE_2 2>&1)"
  if [[ -n "$OUTPUT_2" ]]; then
    echo "Error: Command $CMD_LINE_2 produced unexpected output on branch $branch."
    echo "  Output was: $OUTPUT_2"
    exit 1
  fi

  # 7) If we reach here, all confirmations passed for this branch.
  #    Then clean up and ensure no local modifications.
  # ------------------------------
  echo "All checks passed on branch $branch. Cleaning up..."
  make distclean >/dev/null 2>&1

  # Ensure no local modifications remain (so next branch starts clean).
  git reset --hard HEAD >/dev/null 2>&1
  if [[ $? -ne 0 ]]; then
    echo "Error: Failed to reset branch $branch to a clean state."
    exit 1
  fi
  echo "Branch $branch checks complete. Moving on."
done

echo "All branches have been checked successfully!"
exit 0