#!/usr/bin/env bash
# LEGACY: script ini membuat satu project untuk satu email.
# Skema aktif memakai satu project kelompok untuk lima asisten trainer.
# Lihat ../panduan-setup-project.md sebelum menggunakan script ini.
set -Eeuo pipefail

readonly ROLE_LIST=(
  roles/editor
  roles/resourcemanager.projectIamAdmin
  roles/serviceusage.serviceUsageAdmin
  roles/iam.serviceAccountAdmin
  roles/iam.serviceAccountUser
  roles/compute.osAdminLogin
  roles/iap.tunnelResourceAccessor
  roles/domains.admin
  roles/dns.admin
)

INPUT_FILE=""
BILLING_ACCOUNT_ID=""
START_NUMBER=""
OUTPUT_FILE=""
CURRENT_INDEX=-1

declare -a EMAILS=()
declare -a NUMBERS=()
declare -a PROJECT_IDS=()
declare -a STATUSES=()

usage() {
  cat <<'EOF'
Penggunaan:
  ./create-project-peserta.sh
  ./create-project-peserta.sh --input FILE --billing-account ID --start-number NOMOR [--output FILE]

Mode interaktif meminta Billing Account ID, nomor peserta awal, dan email satu per satu.
Mode file membaca satu email per baris. Baris kosong dan baris yang diawali # diabaikan.

Opsi:
  --input FILE           File daftar email opsional
  --billing-account ID   Billing Account ID dengan format AAAAAA-BBBBBB-CCCCCC
  --start-number NOMOR   Nomor peserta pertama
  --output FILE          Lokasi manifest TSV
  -h, --help             Tampilkan bantuan
EOF
}

die() {
  printf 'ERROR: %s\n' "$1" >&2
  exit 1
}

write_manifest() {
  printf 'nomor\tproject_id\temail\tstatus\n' > "$OUTPUT_FILE"
  local index
  for index in "${!EMAILS[@]}"; do
    printf '%s\t%s\t%s\t%s\n' \
      "${NUMBERS[$index]}" \
      "${PROJECT_IDS[$index]}" \
      "${EMAILS[$index]}" \
      "${STATUSES[$index]}" >> "$OUTPUT_FILE"
  done
}

on_error() {
  local exit_code=$?
  if [[ "$CURRENT_INDEX" -ge 0 && "$CURRENT_INDEX" -lt "${#STATUSES[@]}" ]]; then
    STATUSES[$CURRENT_INDEX]="GAGAL"
    write_manifest
  fi
  if [[ -n "$OUTPUT_FILE" ]]; then
    printf 'Provisioning berhenti. Periksa manifest: %s\n' "$OUTPUT_FILE" >&2
  else
    printf 'Provisioning berhenti sebelum manifest dibuat.\n' >&2
  fi
  exit "$exit_code"
}

mark_failed_and_die() {
  STATUSES[$CURRENT_INDEX]="GAGAL"
  write_manifest
  die "$1"
}

trap on_error ERR

while [[ $# -gt 0 ]]; do
  case "$1" in
    --input)
      [[ $# -ge 2 ]] || die 'Nilai --input belum diberikan.'
      INPUT_FILE="$2"
      shift 2
      ;;
    --billing-account)
      [[ $# -ge 2 ]] || die 'Nilai --billing-account belum diberikan.'
      BILLING_ACCOUNT_ID="$2"
      shift 2
      ;;
    --start-number)
      [[ $# -ge 2 ]] || die 'Nilai --start-number belum diberikan.'
      START_NUMBER="$2"
      shift 2
      ;;
    --output)
      [[ $# -ge 2 ]] || die 'Nilai --output belum diberikan.'
      OUTPUT_FILE="$2"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      die "Opsi tidak dikenal: $1"
      ;;
  esac
done

command -v gcloud >/dev/null 2>&1 || die 'gcloud tidak tersedia. Jalankan script di Google Cloud Shell.'
command -v openssl >/dev/null 2>&1 || die 'openssl tidak tersedia.'

if [[ -z "$BILLING_ACCOUNT_ID" ]]; then
  read -r -p 'Billing Account ID: ' BILLING_ACCOUNT_ID
fi

[[ "$BILLING_ACCOUNT_ID" =~ ^[A-Z0-9]{6}-[A-Z0-9]{6}-[A-Z0-9]{6}$ ]] || \
  die 'Format Billing Account ID tidak valid.'

if [[ -z "$START_NUMBER" ]]; then
  read -r -p 'Nomor peserta awal: ' START_NUMBER
fi

[[ "$START_NUMBER" =~ ^[1-9][0-9]*$ ]] || die 'Nomor peserta awal harus berupa angka positif.'

if [[ -n "$INPUT_FILE" ]]; then
  [[ -f "$INPUT_FILE" ]] || die "File input tidak ditemukan: $INPUT_FILE"
  while IFS= read -r email || [[ -n "$email" ]]; do
    email="${email%$'\r'}"
    [[ -z "$email" || "$email" == \#* ]] && continue
    EMAILS+=("$email")
  done < "$INPUT_FILE"
else
  printf 'Masukkan email peserta satu per satu. Tekan Enter pada baris kosong untuk selesai.\n'
  while true; do
    email=""
    read -r -p "Email peserta $((START_NUMBER + ${#EMAILS[@]})): " email || true
    [[ -z "$email" ]] && break
    EMAILS+=("$email")
  done
fi

[[ "${#EMAILS[@]}" -gt 0 ]] || die 'Tidak ada email peserta untuk diproses.'

for index in "${!EMAILS[@]}"; do
  email="${EMAILS[$index]}"
  [[ "$email" =~ ^[A-Za-z0-9.!#$%\&\'*+/=?^_\`{|}~-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]] || \
    die "Format email tidak valid: $email"

  for previous in "${EMAILS[@]:0:$index}"; do
    [[ "$email" != "$previous" ]] || die "Email ganda dalam batch: $email"
  done
done

ACTIVE_ACCOUNT="$(gcloud auth list --filter=status:ACTIVE --format='value(account)')"
[[ -n "$ACTIVE_ACCOUNT" ]] || die 'Tidak ada akun gcloud yang aktif.'

gcloud billing accounts describe "$BILLING_ACCOUNT_ID" >/dev/null

if [[ -z "$OUTPUT_FILE" ]]; then
  OUTPUT_FILE="hasil-project-$(date '+%Y%m%d-%H%M%S').tsv"
fi

for index in "${!EMAILS[@]}"; do
  participant_number=$((START_NUMBER + index))
  project_id=""

  for attempt in 1 2 3 4 5; do
    suffix="$(openssl rand -hex 3 | cut -c1-5)"
    candidate="geoportal-peserta${participant_number}-${suffix}"
    if ! gcloud projects describe "$candidate" >/dev/null 2>&1; then
      project_id="$candidate"
      break
    fi
  done

  [[ -n "$project_id" ]] || die "Tidak dapat menghasilkan project ID untuk peserta $participant_number."

  NUMBERS+=("$participant_number")
  PROJECT_IDS+=("$project_id")
  STATUSES+=("RENCANA")
done

write_manifest

printf '\nAkun master aktif: %s\n' "$ACTIVE_ACCOUNT"
printf 'Billing Account: %s\n\n' "$BILLING_ACCOUNT_ID"
printf '%-8s %-30s %s\n' 'Nomor' 'Project ID' 'Email'
for index in "${!EMAILS[@]}"; do
  printf '%-8s %-30s %s\n' "${NUMBERS[$index]}" "${PROJECT_IDS[$index]}" "${EMAILS[$index]}"
done
printf '\nManifest awal: %s\n' "$OUTPUT_FILE"

confirmation=""
read -r -p 'Ketik LANJUT untuk membuat project dan IAM: ' confirmation || true
if [[ "$confirmation" != "LANJUT" ]]; then
  printf 'Dibatalkan. Tidak ada project yang dibuat.\n'
  exit 0
fi

for index in "${!EMAILS[@]}"; do
  CURRENT_INDEX="$index"
  participant_number="${NUMBERS[$index]}"
  project_id="${PROJECT_IDS[$index]}"
  participant_email="${EMAILS[$index]}"

  STATUSES[$index]="MEMBUAT_PROJECT"
  write_manifest
  printf '\nMembuat project %s untuk %s\n' "$project_id" "$participant_email"
  gcloud projects create "$project_id" \
    --name="Geoportal Peserta $participant_number"

  STATUSES[$index]="MENGHUBUNGKAN_BILLING"
  write_manifest
  gcloud billing projects link "$project_id" \
    --billing-account="$BILLING_ACCOUNT_ID"

  STATUSES[$index]="MEMBERIKAN_IAM"
  write_manifest
  for role in "${ROLE_LIST[@]}"; do
    gcloud projects add-iam-policy-binding "$project_id" \
      --member="user:$participant_email" \
      --role="$role" \
      --condition=None >/dev/null
  done

  billing_enabled="$(gcloud billing projects describe "$project_id" \
    --format='value(billingEnabled)')"
  case "$billing_enabled" in
    true|True|TRUE) ;;
    *) mark_failed_and_die "Billing belum aktif pada $project_id." ;;
  esac

  assigned_roles="$(gcloud projects get-iam-policy "$project_id" \
    --flatten='bindings[].members' \
    --filter="bindings.members:user:$participant_email" \
    --format='value(bindings.role)')"

  for role in "${ROLE_LIST[@]}"; do
    grep -Fxq "$role" <<< "$assigned_roles" || \
      mark_failed_and_die "Role $role belum tersedia pada $project_id."
  done

  STATUSES[$index]="SELESAI"
  write_manifest
  printf 'Selesai: %s\n' "$project_id"
done

CURRENT_INDEX=-1
printf '\nSemua peserta selesai diproses.\n'
printf 'Simpan dan kirim mapping dari: %s\n' "$OUTPUT_FILE"
