#!/usr/bin/env bash
#
# L0 completeness probe — Phase 2 dim #4 (locked-manageability drift) +
# row-level IsCustomized escape-hatch behavior.
#
# Runs three variants per pack/object/field tuple:
#   TYPE_DRIFT      flip _System_Field.Type, expect verify-pack fatal
#   LENGTH_SILENT   flip _System_Field.MaxLength, observe whether verify catches
#   CUSTOMIZED_BYPASS  set IsCustomized=1 then flip Type, observe whether
#                     row-level flag downgrades drift on a locked component
#
# Usage:
#   ./admin-override-drift.sh <pack-name> <object-api-name> <field-api-name>
# Example:
#   ./admin-override-drift.sh salesforce-crm-standard Account Name
#
# Set SETUP_GO_TAGS when verify-pack must run with distribution-registered L1
# capabilities (for example SETUP_GO_TAGS=crm for salesforce-crm-standard).

set -euo pipefail

PACK="${1:?pack name required}"
OBJECT="${2:?object api name required}"
FIELD="${3:?field api name required}"

: "${TIDB_HOST:=127.0.0.1}"
: "${TIDB_PORT:=4000}"
: "${TIDB_USER:=root}"
: "${TIDB_PASSWORD:=}"
: "${TIDB_DATABASE:=nexuscrm}"
export TIDB_HOST TIDB_PORT TIDB_USER TIDB_PASSWORD TIDB_DATABASE

REPO_ROOT="$(cd "$(dirname "$0")"/../../.. && pwd)"
OUT_DIR="${OUT_DIR:-/tmp/sfmeta/run/phase2/admin-override}"
mkdir -p "$OUT_DIR"
source "$(dirname "$0")/sql-client.sh"
TAG="$(echo "$PACK-$OBJECT-$FIELD" | tr -c 'a-zA-Z0-9-' '-')"
RESULT_TAG="$(printf '%s' "$PACK-$OBJECT-$FIELD" | tr -c 'a-zA-Z0-9-' '-')"
RESULT_JSON="${RESULT_JSON:-$OUT_DIR/$RESULT_TAG-admin-override-drift.json}"

DIM_TYPE_STATUS="fail"
DIM_TYPE_DETAIL="probe did not complete"
DIM_LENGTH_STATUS="fail"
DIM_LENGTH_DETAIL="probe did not complete"
DIM_CUSTOMIZED_STATUS="fail"
DIM_CUSTOMIZED_DETAIL="probe did not complete"
RESULTS_WRITTEN=0

json_escape() {
  printf '%s' "$1" | sed \
    -e 's/\\/\\\\/g' \
    -e 's/"/\\"/g' \
    -e 's/	/\\t/g'
}

write_results_json() {
  cat > "$RESULT_JSON" <<JSON
{
  "schemaVersion": 1,
  "probe": "admin-override-drift",
  "pack": "$(json_escape "$PACK")",
  "object": "$(json_escape "$OBJECT")",
  "field": "$(json_escape "$FIELD")",
  "dimensions": [
    {
      "id": "verify.locked_type_drift_fail_closed",
      "title": "locked field type drift fails verify-pack",
      "status": "$(json_escape "$DIM_TYPE_STATUS")",
      "detail": "$(json_escape "$DIM_TYPE_DETAIL")"
    },
    {
      "id": "verify.locked_max_length_drift_fail_closed",
      "title": "locked field max-length drift fails verify-pack",
      "status": "$(json_escape "$DIM_LENGTH_STATUS")",
      "detail": "$(json_escape "$DIM_LENGTH_DETAIL")"
    },
    {
      "id": "verify.locked_customized_bypass_rejected",
      "title": "row-level IsCustomized does not bypass locked pack verify",
      "status": "$(json_escape "$DIM_CUSTOMIZED_STATUS")",
      "detail": "$(json_escape "$DIM_CUSTOMIZED_DETAIL")"
    }
  ]
}
JSON
  RESULTS_WRITTEN=1
}

fail_all_dimensions() {
  local detail="$1"
  DIM_TYPE_STATUS="fail"
  DIM_TYPE_DETAIL="$detail"
  DIM_LENGTH_STATUS="fail"
  DIM_LENGTH_DETAIL="$detail"
  DIM_CUSTOMIZED_STATUS="fail"
  DIM_CUSTOMIZED_DETAIL="$detail"
}

failed_dimension_count() {
  local count=0
  [[ "$DIM_TYPE_STATUS" == "fail" ]] && count=$((count+1))
  [[ "$DIM_LENGTH_STATUS" == "fail" ]] && count=$((count+1))
  [[ "$DIM_CUSTOMIZED_STATUS" == "fail" ]] && count=$((count+1))
  echo "$count"
}

write_results_on_exit() {
  local rc=$?
  if [[ "$RESULTS_WRITTEN" != "1" ]]; then
    write_results_json || true
    echo "results: $RESULT_JSON" >&2
  fi
  exit "$rc"
}

trap write_results_on_exit EXIT

run_setup() {
  local cmd="$1" name="$2" tag="$3"
  local stdout="$OUT_DIR/${tag}.stdout" stderr="$OUT_DIR/${tag}.stderr"
  local setup_dir="$REPO_ROOT/backend"
  local go_env=()
  local go_tags=()
  if [[ -n "${SETUP_GO_TAGS:-}" ]]; then
    setup_dir="$REPO_ROOT/backend/distributions"
    go_env=(GOWORK=off)
    go_tags=(-tags "$SETUP_GO_TAGS")
  fi
  set +e
  (
    cd "$setup_dir"
    if [[ "${#go_tags[@]}" -gt 0 ]]; then
      env "${go_env[@]}" go run "${go_tags[@]}" ./cmd/setup "$cmd" "$name"
    else
      go run ./cmd/setup "$cmd" "$name"
    fi
  ) \
    > "$stdout" 2> "$stderr"
  local rc=$?
  set -e
  echo "$rc"
}

verify_pack() {
  run_setup verify-pack "$PACK" "$1"
}

field_id() {
  l0_completeness_sql_query "$TIDB_DATABASE" \
    "SELECT f.Id FROM _System_Field f JOIN _System_Object o ON f.ObjectId=o.Id WHERE o.ApiName='$OBJECT' AND f.ApiName='$FIELD' AND f.IsDeleted=0 LIMIT 1;"
}

snapshot_field() {
  l0_completeness_sql_query "$TIDB_DATABASE" \
    "SELECT Type, MaxLength, IsCustomized FROM _System_Field WHERE Id='$1';"
}

set_field_type() {
  l0_completeness_sql_exec "$TIDB_DATABASE" \
    "UPDATE _System_Field SET Type='$2' WHERE Id='$1';"
}
set_field_max_length() {
  l0_completeness_sql_exec "$TIDB_DATABASE" \
    "UPDATE _System_Field SET MaxLength=$2 WHERE Id='$1';"
}
set_field_customized() {
  l0_completeness_sql_exec "$TIDB_DATABASE" \
    "UPDATE _System_Field SET IsCustomized=$2 WHERE Id='$1';"
}

restore_field() {
  l0_completeness_sql_exec "$TIDB_DATABASE" \
    "UPDATE _System_Field SET Type='$2', MaxLength=$3, IsCustomized=$4 WHERE Id='$1';"
}

RC_BASELINE=""
RC_TYPE=""
RC_LENGTH=""
RC_BYPASS=""

echo "=== admin-override-drift: pack=$PACK object=$OBJECT field=$FIELD ==="

FID=$(field_id)
if [[ -z "$FID" ]]; then
  echo "FAIL: field not found in _System_Field" >&2
  fail_all_dimensions "field not found"
  write_results_json
  echo "results: $RESULT_JSON" >&2
  exit 2
fi
echo "field row id: $FID"

ORIG=$(snapshot_field "$FID")
ORIG_TYPE=$(awk 'NR==1{print $1}' <<<"$ORIG")
ORIG_MAXLEN=$(awk 'NR==1{print $2}' <<<"$ORIG")
ORIG_CUSTOM=$(awk 'NR==1{print $3}' <<<"$ORIG")

[[ "$ORIG_MAXLEN" == "NULL" ]] && ORIG_MAXLEN_SQL="NULL" || ORIG_MAXLEN_SQL="$ORIG_MAXLEN"
echo "original: Type=$ORIG_TYPE MaxLength=$ORIG_MAXLEN IsCustomized=$ORIG_CUSTOM"

baseline_rc=$(verify_pack baseline)
RC_BASELINE="$baseline_rc"
echo "[baseline] verify-pack rc=$baseline_rc (expect 0)"
if [[ "$baseline_rc" -ne 0 ]]; then
  echo "FAIL: pre-test baseline drift; aborting" >&2
  fail_all_dimensions "baseline verify-pack failed"
  cat "$OUT_DIR/baseline.stderr"
  write_results_json
  echo "results: $RESULT_JSON" >&2
  exit 2
fi

# --- TYPE_DRIFT ---
case "$ORIG_TYPE" in
  string)   FLIPPED=phone ;;
  phone)    FLIPPED=string ;;
  picklist) FLIPPED=string ;;
  textarea) FLIPPED=string ;;
  *)        FLIPPED=string ;;
esac

echo "--- TYPE_DRIFT: $ORIG_TYPE -> $FLIPPED ---"
DIM_TYPE_STATUS="fail"
DIM_TYPE_DETAIL="started but did not complete"
set_field_type "$FID" "$FLIPPED"
type_rc=$(verify_pack type-drift)
RC_TYPE="$type_rc"
echo "[type-drift] verify-pack rc=$type_rc (expect non-zero)"
restore_field "$FID" "$ORIG_TYPE" "$ORIG_MAXLEN_SQL" "$ORIG_CUSTOM"

# --- LENGTH_SILENT ---
echo "--- LENGTH_SILENT: MaxLength -> 12 ---"
DIM_LENGTH_STATUS="fail"
DIM_LENGTH_DETAIL="started but did not complete"
set_field_max_length "$FID" 12
len_rc=$(verify_pack length-silent)
RC_LENGTH="$len_rc"
echo "[length-silent] verify-pack rc=$len_rc"
restore_field "$FID" "$ORIG_TYPE" "$ORIG_MAXLEN_SQL" "$ORIG_CUSTOM"

# --- CUSTOMIZED_BYPASS ---
echo "--- CUSTOMIZED_BYPASS: IsCustomized=1 + Type -> $FLIPPED ---"
DIM_CUSTOMIZED_STATUS="fail"
DIM_CUSTOMIZED_DETAIL="started but did not complete"
set_field_customized "$FID" 1
set_field_type "$FID" "$FLIPPED"
bypass_rc=$(verify_pack customized-bypass)
RC_BYPASS="$bypass_rc"
echo "[customized-bypass] verify-pack rc=$bypass_rc"
restore_field "$FID" "$ORIG_TYPE" "$ORIG_MAXLEN_SQL" "$ORIG_CUSTOM"

# --- summary ---
echo
echo "=== summary ==="
echo "pack=$PACK object=$OBJECT field=$FIELD"
echo "baseline:           rc=$RC_BASELINE (expect 0)"
echo "type drift:         rc=$RC_TYPE (expect non-zero / fatal)"
echo "max-length drift:   rc=$RC_LENGTH (untracked column probe — gap if 0)"
echo "customized bypass:  rc=$RC_BYPASS (expect non-zero on locked component per contract)"

# Restore final state
restore_field "$FID" "$ORIG_TYPE" "$ORIG_MAXLEN_SQL" "$ORIG_CUSTOM"
final=$(verify_pack final-restore)
echo "post-restore verify rc=$final (expect 0)"

fails=0
if [[ "$RC_TYPE" -eq 0 ]]; then
  DIM_TYPE_STATUS="fail"
  DIM_TYPE_DETAIL="verify-pack returned 0 after locked field Type drift"
  fails=$((fails+1))
else
  DIM_TYPE_STATUS="pass"
  DIM_TYPE_DETAIL="verify-pack failed closed after locked field Type drift"
fi

if [[ "$RC_LENGTH" -eq 0 ]]; then
  DIM_LENGTH_STATUS="fail"
  DIM_LENGTH_DETAIL="verify-pack returned 0 after locked field MaxLength drift"
  fails=$((fails+1))
else
  DIM_LENGTH_STATUS="pass"
  DIM_LENGTH_DETAIL="verify-pack failed closed after locked field MaxLength drift"
fi

if [[ "$RC_BYPASS" -eq 0 ]]; then
  DIM_CUSTOMIZED_STATUS="fail"
  DIM_CUSTOMIZED_DETAIL="verify-pack returned 0 after IsCustomized=1 plus locked field Type drift"
  fails=$((fails+1))
else
  DIM_CUSTOMIZED_STATUS="pass"
  DIM_CUSTOMIZED_DETAIL="verify-pack failed closed after IsCustomized=1 plus locked field Type drift"
fi

if [[ "$final" -ne 0 ]]; then
  echo "FAIL: post-restore verify failed; inspect $OUT_DIR/final-restore.stderr" >&2
  fail_all_dimensions "post-restore verify-pack failed"
fi

fails="$(failed_dimension_count)"
write_results_json
echo "results: $RESULT_JSON" >&2
exit "$fails"
