#!/usr/bin/env bash
set -euo pipefail
export PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/homebrew/bin"

started_at="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
state_dir="${CODEX_INSTALL_STATE_DIR:-${TMPDIR:-/tmp}/baijimu-codex-install}"
status_path="$state_dir/status.json"
result_path="$state_dir/result.json"
mkdir -p "$state_dir"

current_step=0
step_count=7
step1_name="Check ChatGPT desktop app"; step1_state="pending"; step1_detail=""; step1_downloaded=""; step1_total=""
step2_name="Read package manifest"; step2_state="pending"; step2_detail=""; step2_downloaded=""; step2_total=""
step3_name="Download ChatGPT package"; step3_state="pending"; step3_detail=""; step3_downloaded=""; step3_total=""
step4_name="Verify package"; step4_state="pending"; step4_detail=""; step4_downloaded=""; step4_total=""
step5_name="Mount package"; step5_state="pending"; step5_detail=""; step5_downloaded=""; step5_total=""
step6_name="Install ChatGPT desktop app"; step6_state="pending"; step6_detail=""; step6_downloaded=""; step6_total=""
step7_name="Open ChatGPT desktop app"; step7_state="pending"; step7_detail=""; step7_downloaded=""; step7_total=""
target_app_path="/Applications/ChatGPT.app"
legacy_app_path="/Applications/Codex.app"

json_escape() {
  printf '%s' "${1:-}" | awk 'BEGIN { ORS = ""; first = 1 } {
    if (!first) { printf "\\n" }
    first = 0
    gsub(/\\/, "\\\\")
    gsub(/"/, "\\\"")
    gsub(/\r/, "\\r")
    gsub(/\t/, "\\t")
    printf "%s", $0
  }'
}

json_string() {
  printf '"'
  json_escape "${1:-}"
  printf '"'
}

json_number_or_null() {
  case "${1:-}" in
    ""|*[!0-9]*) printf 'null' ;;
    *) printf '%s' "$1" ;;
  esac
}

write_install_console() {
  [ "${CODEX_INSTALL_QUIET:-}" = "1" ] && return 0
  printf '%s\n' "$*" >&2
}

write_status() {
  {
    printf '{\n'
    printf '  "title": "Baijimu is installing ChatGPT desktop app",\n'
    printf '  "platform": "macos",\n'
    printf '  "startedAt": '; json_string "$started_at"; printf ',\n'
    printf '  "updatedAt": '; json_string "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"; printf ',\n'
    printf '  "currentStep": %s,\n' "$current_step"
    printf '  "statusPath": '; json_string "$status_path"; printf ',\n'
    printf '  "resultPath": '; json_string "$result_path"; printf ',\n'
    printf '  "steps": [\n'
    for index in 1 2 3 4 5 6 7; do
      eval "name=\${step${index}_name}"
      eval "state=\${step${index}_state}"
      eval "detail=\${step${index}_detail}"
      eval "downloaded=\${step${index}_downloaded}"
      eval "total=\${step${index}_total}"
      printf '    { "index": %s, "name": ' "$index"; json_string "$name"; printf ', "state": '; json_string "$state"
      printf ', "detail": '; json_string "$detail"; printf ', "downloadedBytes": '; json_number_or_null "$downloaded"
      printf ', "totalBytes": '; json_number_or_null "$total"; printf ' }'
      [ "$index" -lt "$step_count" ] && printf ','
      printf '\n'
    done
    printf '  ]\n'
    printf '}\n'
  } > "$status_path"
}

set_step() {
  index="$1"
  state="$2"
  detail="${3:-}"
  downloaded="${4:-}"
  total="${5:-}"
  current_step="$index"
  eval "step${index}_state=\$state"
  eval "step${index}_detail=\$detail"
  eval "step${index}_downloaded=\$downloaded"
  eval "step${index}_total=\$total"
  write_status

  eval "name=\${step${index}_name}"
  label="[$index/$step_count] $name"
  if [ -n "$downloaded" ] && [ -n "$total" ] && [ "$total" -gt 0 ] 2>/dev/null; then
    downloaded_mb="$(awk -v bytes="$downloaded" 'BEGIN { printf "%.1f", bytes / 1024 / 1024 }')"
    total_mb="$(awk -v bytes="$total" 'BEGIN { printf "%.1f", bytes / 1024 / 1024 }')"
    write_install_console "$label  $state  ${downloaded_mb}MB / ${total_mb}MB"
  elif [ -n "$detail" ]; then
    write_install_console "$label  $state  $detail"
  else
    write_install_console "$label  $state"
  fi
}

finish_result() {
  ok="$1"
  app_installed="$2"
  app_install_method="$3"
  asset_name="${4:-}"
  version="${5:-}"
  bundle_id="${6:-}"
  error_message="${7:-}"
  app_path="${RESULT_APP_PATH:-$target_app_path}"
  elapsed_ms="$(( ($(date +%s) - start_epoch) * 1000 ))"
  {
    printf '{\n'
    printf '  "ok": %s,\n' "$ok"
    printf '  "platform": "macos",\n'
    printf '  "startedAt": '; json_string "$started_at"; printf ',\n'
    printf '  "appInstalled": %s,\n' "$app_installed"
    printf '  "appInstallMethod": '; json_string "$app_install_method"; printf ',\n'
    printf '  "appPath": '; json_string "$app_path"; printf ',\n'
    printf '  "asset": '; json_string "$asset_name"; printf ',\n'
    printf '  "version": '; json_string "$version"; printf ',\n'
    printf '  "bundleId": '; json_string "$bundle_id"; printf ',\n'
    printf '  "elapsedMs": %s,\n' "$elapsed_ms"
    if [ -n "$error_message" ]; then
      printf '  "warnings": [],\n'
      printf '  "errors": [ '; json_string "$error_message"; printf ' ]\n'
    else
      printf '  "warnings": [],\n'
      printf '  "errors": []\n'
    fi
    printf '}\n'
  } > "$result_path"
  cat "$result_path"
}

download_with_progress() {
  url="$1"
  output="$2"
  step="$3"
  label="$4"
  total="${5:-}"
  rm -f "$output"
  : > "$output"
  set_step "$step" "running" "$label" "" "$total"
  curl -fL --silent --show-error "$url" -o "$output" &
  curl_pid="$!"
  while kill -0 "$curl_pid" 2>/dev/null; do
    size="$(stat -f '%z' "$output" 2>/dev/null || printf '0')"
    set_step "$step" "running" "$label" "$size" "$total"
    sleep 1
  done
  wait "$curl_pid"
  size="$(stat -f '%z' "$output" 2>/dev/null || printf '0')"
  set_step "$step" "completed" "$label" "$size" "$total"
}

installed_app_path() {
  if [ -d "$target_app_path" ]; then
    printf '%s\n' "$target_app_path"
  elif [ -d "$legacy_app_path" ]; then
    printf '%s\n' "$legacy_app_path"
  fi
}

start_epoch="$(date +%s)"
manifest_url="https://lowcode-common.oss-cn-beijing.aliyuncs.com/codex-artifacts/latest.json"
arch="$(uname -m)"
case "$arch" in
  arm64) asset="codex-app-aarch64-apple-darwin.dmg" ;;
  x86_64) asset="codex-app-x86_64-apple-darwin.dmg" ;;
  *) finish_result false false "baijimu-cache-dmg" "" "" "" "Baijimu cache does not include this macOS architecture: $arch" >&1; exit 1 ;;
esac

work_dir="$(mktemp -d "${TMPDIR:-/tmp}/codex-app.XXXXXX")"
mount_dir=""
cleanup() {
  if [ -n "${mount_dir:-}" ] && mount | grep -Fq "$mount_dir"; then
    hdiutil detach "$mount_dir" -quiet || true
  fi
  rm -rf "$work_dir"
}
trap cleanup EXIT

write_install_console ""
write_install_console "Baijimu is installing ChatGPT desktop app"
write_install_console "Please keep this window open."
write_install_console ""
write_status

existing_app_path="$(installed_app_path)"
if [ -n "$existing_app_path" ]; then
  RESULT_APP_PATH="$existing_app_path"
  set_step 1 "completed" "ChatGPT desktop app is already installed"
  version="$(mdls -raw -name kMDItemVersion "$existing_app_path" 2>/dev/null || true)"
  bundle_id="$(mdls -raw -name kMDItemCFBundleIdentifier "$existing_app_path" 2>/dev/null || true)"
  set_step 2 "skipped" "Package download is not needed"
  set_step 3 "skipped" "Package download is not needed"
  set_step 4 "skipped" "Package verification is not needed"
  set_step 5 "skipped" "Package mount is not needed"
  set_step 6 "skipped" "Reinstall is not needed"
  set_step 7 "running" "Opening ChatGPT desktop app"
  open "$existing_app_path" || true
  set_step 7 "completed" "ChatGPT desktop app opened"
  write_install_console ""
  write_install_console "ChatGPT desktop app install step completed. You can close this window."
  finish_result true true "already-installed" "" "$version" "$bundle_id" ""
  exit 0
fi

set_step 1 "completed" "ChatGPT desktop app is not installed; preparing install"
manifest="$work_dir/latest.json"
dmg="$work_dir/$asset"

download_with_progress "$manifest_url" "$manifest" 2 "Reading Baijimu package manifest" ""
asset_block="$(awk -v name="$asset" '
  $0 ~ "\"name\"[[:space:]]*:[[:space:]]*\"" name "\"" { found = 1 }
  found { print }
  found && $0 ~ /^[[:space:]]*}[,]?[[:space:]]*$/ { exit }
' "$manifest")"

mirror_url="$(printf '%s\n' "$asset_block" | awk -F'"' '/"mirror_url"[[:space:]]*:/ { print $4; exit }')"
sha256="$(printf '%s\n' "$asset_block" | awk -F'"' '/"sha256"[[:space:]]*:/ { print $4; exit }')"
size_bytes="$(printf '%s\n' "$asset_block" | awk -F'[: ,]+' '/"size_bytes"[[:space:]]*:/ { gsub(/[^0-9]/, "", $3); print $3; exit }')"
[ -z "$size_bytes" ] && size_bytes="$(printf '%s\n' "$asset_block" | awk -F'[: ,]+' '/"size"[[:space:]]*:/ { gsub(/[^0-9]/, "", $3); print $3; exit }')"

if [ -z "$mirror_url" ] || [ -z "$sha256" ]; then
  finish_result false false "baijimu-cache-dmg" "$asset" "" "" "Baijimu cache asset is missing or incomplete: $asset" >&1
  exit 1
fi

set_step 2 "completed" "Found $asset"
download_with_progress "$mirror_url" "$dmg" 3 "Downloading official ChatGPT desktop app package" "$size_bytes"

set_step 4 "running" "Verifying package SHA256"
actual="$(shasum -a 256 "$dmg" | awk '{print $1}')"
if [ "$actual" != "$sha256" ]; then
  finish_result false false "baijimu-cache-dmg" "$asset" "" "" "SHA256 mismatch for $asset" >&1
  exit 1
fi
set_step 4 "completed" "Package SHA256 verified"

set_step 5 "running" "Mounting ChatGPT DMG"
mount_dir="$(mktemp -d "${TMPDIR:-/tmp}/codex-dmg.XXXXXX")"
hdiutil attach "$dmg" -mountpoint "$mount_dir" -nobrowse -quiet
if [ -d "$mount_dir/ChatGPT.app" ]; then
  source_app="$mount_dir/ChatGPT.app"
elif [ -d "$mount_dir/Codex.app" ]; then
  source_app="$mount_dir/Codex.app"
else
  source_app="$(find "$mount_dir" -maxdepth 1 -name '*.app' -type d | head -n 1)"
fi
[ -n "${source_app:-}" ] && [ -d "$source_app" ] || { finish_result false false "baijimu-cache-dmg" "$asset" "" "" "No supported app bundle found in DMG" >&1; exit 1; }
target_app="/Applications/$(basename "$source_app")"
RESULT_APP_PATH="$target_app"
set_step 5 "completed" "ChatGPT DMG mounted"

set_step 6 "running" "Copying ChatGPT desktop app to Applications"
ditto "$source_app" "$target_app"
hdiutil detach "$mount_dir" -quiet
mount_dir=""
xattr -dr com.apple.quarantine "$target_app" 2>/dev/null || true
test -d "$target_app"
version="$(mdls -raw -name kMDItemVersion "$target_app" 2>/dev/null || true)"
bundle_id="$(mdls -raw -name kMDItemCFBundleIdentifier "$target_app" 2>/dev/null || true)"
set_step 6 "completed" "ChatGPT desktop app installed"

set_step 7 "running" "Opening ChatGPT desktop app"
open "$target_app"
set_step 7 "completed" "ChatGPT desktop app opened"
write_install_console ""
write_install_console "ChatGPT desktop app install step completed. You can close this window."
finish_result true true "baijimu-cache-dmg" "$asset" "$version" "$bundle_id" ""
