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

ROOT="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
ENV_FILE="${2:-$ROOT/.env}"
CANARY_TEST="${3:-$ROOT/tests/workshop_midtrans_sandbox_canary.py}"
if [[ ! -r "$ENV_FILE" ]]; then
  echo "Environment file is not readable: $ENV_FILE" >&2
  exit 2
fi
if [[ ! -r "$CANARY_TEST" ]]; then
  echo "Canary test file is not readable: $CANARY_TEST" >&2
  exit 2
fi

read_env() {
  local key="$1"
  awk -F= -v key="$key" '$1 == key {sub(/^[^=]*=/, ""); print; exit}' "$ENV_FILE"
}

DB_HOST="$(read_env DB_HOST)"
DB_PORT="$(read_env DB_PORT)"
DB_USER="$(read_env DB_USER)"
DB_PASS="$(read_env DB_PASS)"
SANDBOX_SERVER_KEY="$(read_env MIDTRANS_SANDBOX_SERVER_KEY)"
if [[ -z "$SANDBOX_SERVER_KEY" || "$SANDBOX_SERVER_KEY" == "change_me" ]]; then
  echo "Midtrans sandbox server key is not configured" >&2
  exit 2
fi

STAMP="$(date -u +%Y%m%d%H%M%S)"
TEST_DB="yokesen_midtrans_canary_${STAMP}"
HTTP_ROOT="${ROOT}-sandbox-${TEST_DB}"
STATE_FILE="$HTTP_ROOT/canary-state.json"
HTTP_PID=""
MYSQL_ROOT=(mysql)
MYSQL_APP=(mysql -h "$DB_HOST" -P "${DB_PORT:-3306}" -u "$DB_USER" "-p$DB_PASS")

cleanup() {
  local exit_status=$?
  if [[ -n "$HTTP_PID" ]]; then
    kill "$HTTP_PID" >/dev/null 2>&1 || true
    wait "$HTTP_PID" 2>/dev/null || true
  fi
  if [[ "$exit_status" -ne 0 && -f "$HTTP_ROOT/http.log" ]]; then
    echo "--- Midtrans canary HTTP log ---" >&2
    tail -n 120 "$HTTP_ROOT/http.log" >&2 || true
  fi
  if [[ "$HTTP_ROOT" == "${ROOT}-sandbox-yokesen_midtrans_canary_"* ]]; then
    rm -rf "$HTTP_ROOT"
  fi
  "${MYSQL_ROOT[@]}" -e "DROP DATABASE IF EXISTS \`$TEST_DB\`;" >/dev/null 2>&1 || true
}
trap cleanup EXIT

"${MYSQL_ROOT[@]}" -e "CREATE DATABASE \`$TEST_DB\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; GRANT ALL PRIVILEGES ON \`$TEST_DB\`.* TO '$DB_USER'@'localhost'; FLUSH PRIVILEGES;"
for migration in 000_migration_registry.sql 001_init.sql 002_auth.sql 003_workshop_commercial.sql 004_workshop_booking_payment.sql 005_workshop_payment_lifecycle.sql; do
  "${MYSQL_APP[@]}" "$TEST_DB" < "$ROOT/migrations/$migration"
done

cp -a "$ROOT" "$HTTP_ROOT"
install -m 0644 "$CANARY_TEST" "$HTTP_ROOT/tests/workshop_midtrans_sandbox_canary.py"
rm -f "$HTTP_ROOT/.env"
awk -v db="$TEST_DB" '
  BEGIN { service=0; hmac=0; booking=0; payment=0; privacy=0; mode=0; challenge=0; debug=0 }
  /^DB_NAME=/ { print "DB_NAME=" db; next }
  /^COMMERCIAL_API_ENABLED=/ { print "COMMERCIAL_API_ENABLED=true"; next }
  /^COMMERCIAL_SERVICE_TOKEN=/ { print "COMMERCIAL_SERVICE_TOKEN=midtrans-sandbox-canary-service"; service=1; next }
  /^COMMERCIAL_CONTEXT_HMAC_SECRET=/ { print "COMMERCIAL_CONTEXT_HMAC_SECRET=midtrans-sandbox-canary-hmac-secret-32-bytes"; hmac=1; next }
  /^WORKSHOP_BOOKING_API_ENABLED=/ { print "WORKSHOP_BOOKING_API_ENABLED=true"; booking=1; next }
  /^WORKSHOP_PAYMENT_API_ENABLED=/ { print "WORKSHOP_PAYMENT_API_ENABLED=true"; payment=1; next }
  /^WORKSHOP_PRIVACY_POLICY_VERSION=/ { print "WORKSHOP_PRIVACY_POLICY_VERSION=2026-07-18"; privacy=1; next }
  /^MIDTRANS_MODE=/ { print "MIDTRANS_MODE=sandbox"; mode=1; next }
  /^MIDTRANS_STATUS_CHALLENGE_ENABLED=/ { print "MIDTRANS_STATUS_CHALLENGE_ENABLED=true"; challenge=1; next }
  /^APP_DEBUG=/ { print "APP_DEBUG=true"; debug=1; next }
  { print }
  END {
    if (!service) print "COMMERCIAL_SERVICE_TOKEN=midtrans-sandbox-canary-service"
    if (!hmac) print "COMMERCIAL_CONTEXT_HMAC_SECRET=midtrans-sandbox-canary-hmac-secret-32-bytes"
    if (!booking) print "WORKSHOP_BOOKING_API_ENABLED=true"
    if (!payment) print "WORKSHOP_PAYMENT_API_ENABLED=true"
    if (!privacy) print "WORKSHOP_PRIVACY_POLICY_VERSION=2026-07-18"
    if (!mode) print "MIDTRANS_MODE=sandbox"
    if (!challenge) print "MIDTRANS_STATUS_CHALLENGE_ENABLED=true"
    if (!debug) print "APP_DEBUG=true"
  }
' "$ENV_FILE" > "$HTTP_ROOT/.env"
chmod 600 "$HTTP_ROOT/.env"

HTTP_PORT=$((19000 + RANDOM % 800))
php -S "127.0.0.1:$HTTP_PORT" -t "$HTTP_ROOT/public" "$HTTP_ROOT/public/index.php" >"$HTTP_ROOT/http.log" 2>&1 &
HTTP_PID=$!
for _ in {1..40}; do
  if curl -fsS "http://127.0.0.1:$HTTP_PORT/health" >/dev/null; then
    break
  fi
  sleep 0.2
done
curl -fsS "http://127.0.0.1:$HTTP_PORT/health" >/dev/null

python3 "$HTTP_ROOT/tests/workshop_midtrans_sandbox_canary.py" \
  "http://127.0.0.1:$HTTP_PORT" midtrans-sandbox-canary-service "$STATE_FILE" create

PAYMENT_ID="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["payment_id"])' "$STATE_FILE")"
PROVIDER_ORDER_ID="$("${MYSQL_APP[@]}" -N "$TEST_DB" -e "SELECT provider_order_id FROM workshop_payments WHERE payment_id='${PAYMENT_ID}' LIMIT 1")"
if [[ -z "$PROVIDER_ORDER_ID" ]]; then
  echo "Canary payment provider order was not persisted" >&2
  exit 1
fi

echo "CANARY_WAITING_FOR_BCA_SIMULATOR"
PROVIDER_STATUS=""
for _ in {1..300}; do
  STATUS_JSON="$(curl -fsS -u "$SANDBOX_SERVER_KEY:" "https://api.sandbox.midtrans.com/v2/${PROVIDER_ORDER_ID}/status")"
  PROVIDER_STATUS="$(printf '%s' "$STATUS_JSON" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("transaction_status", ""))')"
  if [[ "$PROVIDER_STATUS" == "settlement" || "$PROVIDER_STATUS" == "capture" ]]; then
    printf '%s' "$STATUS_JSON" > "$HTTP_ROOT/provider-status.json"
    break
  fi
  sleep 2
done
if [[ "$PROVIDER_STATUS" != "settlement" && "$PROVIDER_STATUS" != "capture" ]]; then
  echo "Midtrans sandbox payment did not reach a paid provider state" >&2
  exit 1
fi

FIRST_NOTIFICATION="$(curl -fsS -X POST -H 'Content-Type: application/json' --data-binary @"$HTTP_ROOT/provider-status.json" "http://127.0.0.1:$HTTP_PORT/api/midtrans/notification")"
SECOND_NOTIFICATION="$(curl -fsS -X POST -H 'Content-Type: application/json' --data-binary @"$HTTP_ROOT/provider-status.json" "http://127.0.0.1:$HTTP_PORT/api/v1/workshop-payments/midtrans/notification")"
printf '%s' "$FIRST_NOTIFICATION" | python3 -c 'import json,sys; p=json.load(sys.stdin); assert p.get("ok") is True and p.get("payment_status") == "paid", p'
printf '%s' "$SECOND_NOTIFICATION" | python3 -c 'import json,sys; p=json.load(sys.stdin); assert p.get("ok") is True and p.get("duplicate") is True, p'

python3 "$HTTP_ROOT/tests/workshop_midtrans_sandbox_canary.py" \
  "http://127.0.0.1:$HTTP_PORT" midtrans-sandbox-canary-service "$STATE_FILE" verify

CARD_STATE_FILE="$HTTP_ROOT/card-canary-state.json"
python3 "$HTTP_ROOT/tests/workshop_midtrans_sandbox_canary.py" \
  "http://127.0.0.1:$HTTP_PORT" midtrans-sandbox-canary-service "$CARD_STATE_FILE" card_prepare
echo "CANARY_WAITING_FOR_BROWSER_CARD_TOKEN"
IFS= read -r CARD_TOKEN
if [[ -z "$CARD_TOKEN" ]]; then
  echo "Browser did not provide a Midtrans sandbox card token" >&2
  exit 1
fi
MIDTRANS_CARD_TOKEN="$CARD_TOKEN" python3 "$HTTP_ROOT/tests/workshop_midtrans_sandbox_canary.py" \
  "http://127.0.0.1:$HTTP_PORT" midtrans-sandbox-canary-service "$CARD_STATE_FILE" card_charge

CARD_PAYMENT_ID="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["payment_id"])' "$CARD_STATE_FILE")"
CARD_PROVIDER_ORDER_ID="$("${MYSQL_APP[@]}" -N "$TEST_DB" -e "SELECT provider_order_id FROM workshop_payments WHERE payment_id='${CARD_PAYMENT_ID}' LIMIT 1")"
if [[ -z "$CARD_PROVIDER_ORDER_ID" ]]; then
  echo "Card canary provider order was not persisted" >&2
  exit 1
fi
echo "CANARY_WAITING_FOR_3DS_AUTHENTICATION"
CARD_PROVIDER_STATUS=""
for _ in {1..300}; do
  CARD_STATUS_JSON="$(curl -fsS -u "$SANDBOX_SERVER_KEY:" "https://api.sandbox.midtrans.com/v2/${CARD_PROVIDER_ORDER_ID}/status")"
  CARD_PROVIDER_STATUS="$(printf '%s' "$CARD_STATUS_JSON" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("transaction_status", ""))')"
  if [[ "$CARD_PROVIDER_STATUS" == "settlement" || "$CARD_PROVIDER_STATUS" == "capture" ]]; then
    printf '%s' "$CARD_STATUS_JSON" > "$HTTP_ROOT/card-provider-status.json"
    break
  fi
  sleep 2
done
if [[ "$CARD_PROVIDER_STATUS" != "settlement" && "$CARD_PROVIDER_STATUS" != "capture" ]]; then
  echo "Midtrans 3DS card canary did not reach a paid provider state" >&2
  exit 1
fi

CARD_NOTIFICATION="$(curl -fsS -X POST -H 'Content-Type: application/json' --data-binary @"$HTTP_ROOT/card-provider-status.json" "http://127.0.0.1:$HTTP_PORT/api/v1/workshop-payments/midtrans/notification")"
printf '%s' "$CARD_NOTIFICATION" | python3 -c 'import json,sys; p=json.load(sys.stdin); assert p.get("ok") is True and p.get("payment_status") == "paid", p'
python3 "$HTTP_ROOT/tests/workshop_midtrans_sandbox_canary.py" \
  "http://127.0.0.1:$HTTP_PORT" midtrans-sandbox-canary-service "$CARD_STATE_FILE" card_verify

VA_BOOKING_REFERENCE="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["booking_reference"])' "$STATE_FILE")"
CARD_BOOKING_REFERENCE="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["booking_reference"])' "$CARD_STATE_FILE")"
CRM_PAID_COUNT="$("${MYSQL_APP[@]}" -N "$TEST_DB" -e "SELECT COUNT(*) FROM crm_opportunities c JOIN workshop_bookings b ON b.opportunity_id=c.opportunity_id WHERE b.booking_reference IN ('${VA_BOOKING_REFERENCE}','${CARD_BOOKING_REFERENCE}') AND c.stage='paid'")"
PAYMENT_OUTBOX_COUNT="$("${MYSQL_APP[@]}" -N "$TEST_DB" -e "SELECT COUNT(*) FROM workshop_notification_outbox n JOIN workshop_bookings b ON b.booking_id=n.booking_id WHERE b.booking_reference IN ('${VA_BOOKING_REFERENCE}','${CARD_BOOKING_REFERENCE}') AND n.template_code='workshop_payment_received'")"
OFFER_OUTBOX_COUNT="$("${MYSQL_APP[@]}" -N "$TEST_DB" -e "SELECT COUNT(*) FROM workshop_notification_outbox n JOIN workshop_bookings b ON b.booking_id=n.booking_id WHERE b.booking_reference IN ('${VA_BOOKING_REFERENCE}','${CARD_BOOKING_REFERENCE}') AND n.template_code='workshop_offer_and_invoice'")"
PAYMENT_OUTBOX_DUPLICATES="$("${MYSQL_APP[@]}" -N "$TEST_DB" -e "SELECT COUNT(*) FROM (SELECT n.booking_id FROM workshop_notification_outbox n JOIN workshop_bookings b ON b.booking_id=n.booking_id WHERE b.booking_reference IN ('${VA_BOOKING_REFERENCE}','${CARD_BOOKING_REFERENCE}') AND n.template_code='workshop_payment_received' GROUP BY n.booking_id HAVING COUNT(*) > 1) duplicate_notifications")"
if [[ "$CRM_PAID_COUNT" -ne 2 || "$PAYMENT_OUTBOX_COUNT" -ne 2 || "$OFFER_OUTBOX_COUNT" -ne 2 || "$PAYMENT_OUTBOX_DUPLICATES" -ne 0 ]]; then
  echo "Sandbox canary CRM/outbox reconciliation failed (crm_paid=$CRM_PAID_COUNT, paid_outbox=$PAYMENT_OUTBOX_COUNT, offer_outbox=$OFFER_OUTBOX_COUNT, duplicate_paid=$PAYMENT_OUTBOX_DUPLICATES)" >&2
  exit 1
fi

echo "verify_midtrans_sandbox_canary: PASS (VA + browser-tokenized 3DS card, canonical+legacy signed webhooks, duplicate, reconcile, restore, CRM, outbox, Works state)"
