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

ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
APP_DIR="$ROOT_DIR"
PUBSPEC_PATH="$ROOT_DIR/pubspec.yaml"
DIST_DIR="$ROOT_DIR/dist"
APP_NAME="${APP_NAME:-XWorkmate}"
BUILD_MODE="${BUILD_MODE:-release}"
APP_STORE_DEFINE="${APP_STORE_DEFINE:---dart-define=XWORKMATE_APP_STORE=${XWORKMATE_APP_STORE:-true}}"
SIGN_IDENTITY="${XWORKMATE_SIGN_IDENTITY:-}"
PRODUCTS_DIR_NAME="$(tr '[:lower:]' '[:upper:]' <<< "${BUILD_MODE:0:1}")${BUILD_MODE:1}"
FLUTTER_BUILD_STATE_DIR="${ROOT_DIR}/.dart_tool/flutter_build"
MACOS_BUILD_DIR="${ROOT_DIR}/build/macos"
NATIVE_ASSETS_DIR="${ROOT_DIR}/build/native_assets"
MACOS_PROJECT_FILE="$ROOT_DIR/macos/Runner.xcodeproj/project.pbxproj"
MACOS_APP_INFO_CONFIG="$ROOT_DIR/macos/Runner/Configs/AppInfo.xcconfig"
source "$ROOT_DIR/scripts/ci/apple_signing.sh"
APPLE_SIGNING_CLEANUP_COMMANDS=()
MACOS_SIGNING_PATCH_BACKUPS=()

cleanup_package_macos() {
  local entry original backup
  for entry in "${MACOS_SIGNING_PATCH_BACKUPS[@]}"; do
    original="${entry%%::*}"
    backup="${entry#*::}"
    if [[ -f "$backup" ]]; then
      mv "$backup" "$original"
    fi
  done
  apple_run_cleanup
}

trap cleanup_package_macos EXIT

remove_tree_with_retries() {
  local path="$1"
  local attempts="${2:-5}"
  local delay_seconds="${3:-1}"
  local try=1

  [[ -e "$path" ]] || return 0

  while (( try <= attempts )); do
    chmod -R u+w "$path" 2>/dev/null || true
    rm -rf "$path" 2>/dev/null || true

    if [[ ! -e "$path" ]]; then
      return 0
    fi

    if (( try == attempts )); then
      echo "Failed to remove generated path after ${attempts} attempts: $path" >&2
      return 1
    fi

    sleep "$delay_seconds"
    ((try++))
  done
}

backup_for_signing_patch() {
  local path="$1"
  local backup

  [[ -f "$path" ]] || return 0
  backup="$(mktemp "${RUNNER_TEMP:-/tmp}/xworkmate-macos-signing.XXXXXX")"
  cp "$path" "$backup"
  MACOS_SIGNING_PATCH_BACKUPS+=("${path}::${backup}")
}

patch_macos_project_for_ad_hoc_signing() {
  echo "Patching macOS project for ad-hoc signing during unsigned CI build..."
  backup_for_signing_patch "$MACOS_PROJECT_FILE"
  backup_for_signing_patch "$MACOS_APP_INFO_CONFIG"

  if [[ -f "$MACOS_PROJECT_FILE" ]]; then
    perl -0pi -e 's/"CODE_SIGN_IDENTITY\[sdk=macosx\*\]" = "Apple Development";/CODE_SIGN_IDENTITY = "-";/g; s/CODE_SIGN_STYLE = Automatic;/CODE_SIGN_STYLE = Manual;/g; s/DEVELOPMENT_TEAM = [^;]+;/DEVELOPMENT_TEAM = "";/g' "$MACOS_PROJECT_FILE"
  fi

  if [[ -f "$MACOS_APP_INFO_CONFIG" ]]; then
    perl -0pi -e 's/^DEVELOPMENT_TEAM = .*$/DEVELOPMENT_TEAM =/mg' "$MACOS_APP_INFO_CONFIG"
  fi
}

if [[ ! -f "$PUBSPEC_PATH" ]]; then
  echo "Missing pubspec: $PUBSPEC_PATH" >&2
  exit 1
fi

eval "$(python3 "$ROOT_DIR/scripts/ci/build_version.py" --format shell)"
BUILD_DATE_LINE="$(sed -n 's/^build-date:[[:space:]]*//p' "$PUBSPEC_PATH" | head -n 1)"
BUILD_ID_LINE="$(sed -n 's/^build-id:[[:space:]]*//p' "$PUBSPEC_PATH" | head -n 1)"
GIT_BUILD_DATE="$(cd "$ROOT_DIR" && git show -s --format=%cs HEAD 2>/dev/null || true)"
GIT_BUILD_COMMIT="$(cd "$ROOT_DIR" && git rev-parse --short HEAD 2>/dev/null || true)"

APP_VERSION="$DISPLAY_VERSION"
APP_RELEASE_VERSION="$PLATFORM_RELEASE_VERSION"
APP_BUILD="$BUILD_NUMBER"
APP_BUILD_DATE="${GIT_BUILD_DATE:-${BUILD_DATE_LINE:-unknown}}"
APP_BUILD_COMMIT="${GIT_BUILD_COMMIT:-${BUILD_ID_LINE:-unknown}}"

BUILD_APP_PATH="$APP_DIR/build/macos/Build/Products/$PRODUCTS_DIR_NAME/$APP_NAME.app"
DIST_APP_PATH="$DIST_DIR/$APP_NAME.app"
DIST_DMG_PATH="$DIST_DIR/$APP_NAME-$APP_VERSION.dmg"
mkdir -p "$DIST_DIR"

echo "Building $APP_NAME $APP_VERSION ($APP_BUILD) for macOS..."
# Flutter caches native-asset installation state under .dart_tool/flutter_build,
# but Xcode consumes the copied frameworks from build/native_assets/macos.
# Reset both locations so packaging cannot reuse a stale stamp or stale layout.
remove_tree_with_retries "$FLUTTER_BUILD_STATE_DIR"
remove_tree_with_retries "$MACOS_BUILD_DIR"
remove_tree_with_retries "$NATIVE_ASSETS_DIR"

if [[ -n "${APPLE_CERT_P12_BASE64:-}" &&
      -n "${APPLE_CERT_PASSWORD:-}" &&
      -n "${APPLE_KEYCHAIN_PASSWORD:-}" ]]; then
  echo "Provisioning Apple signing certificate for macOS build..."
  apple_setup_signing_keychain
else
  echo "Apple signing secrets not set; building macOS app with ad-hoc signing."
  patch_macos_project_for_ad_hoc_signing
fi

BUILD_ARGS=(
  flutter build macos
  "--$BUILD_MODE"
  --build-name="$APP_RELEASE_VERSION"
  --build-number="$APP_BUILD"
  --dart-define="XWORKMATE_DISPLAY_VERSION=$APP_VERSION"
  --dart-define="XWORKMATE_BUILD_NUMBER=$APP_BUILD"
  --dart-define="XWORKMATE_BUILD_DATE=$APP_BUILD_DATE"
  --dart-define="XWORKMATE_BUILD_COMMIT=$APP_BUILD_COMMIT"
  "$APP_STORE_DEFINE"
)

(
  cd "$APP_DIR"
  "${BUILD_ARGS[@]}"
)

if [[ ! -d "$BUILD_APP_PATH" ]]; then
  echo "Expected app bundle not found: $BUILD_APP_PATH" >&2
  exit 1
fi

verify_bundle_signature() {
  local app_path="$1"
  echo "Verifying code signature: $app_path"
  codesign --verify --deep --verbose=2 "$app_path"
}

validate_bundle_dependencies() {
  local app_path="$1"
  bash "$ROOT_DIR/scripts/validate-macos-app-bundle.sh" "$app_path"
}

echo "Validating export compliance metadata..."
bash "$ROOT_DIR/scripts/check-apple-export-compliance.sh" "$BUILD_APP_PATH"
validate_bundle_dependencies "$BUILD_APP_PATH"

rm -rf "$DIST_APP_PATH" "$DIST_DMG_PATH"
ditto "$BUILD_APP_PATH" "$DIST_APP_PATH"

echo "Re-signing app bundle to account for manual additions..."
# Components must be signed from inside out.
# 1. Sign all dylibs and frameworks
find "$DIST_APP_PATH/Contents/Frameworks" -name "*.dylib" -type f | while read -r dylib; do
  echo "Signing nested dylib: $dylib"
  codesign --force --sign "${SIGN_IDENTITY:--}" --timestamp=none "$dylib"
done

find "$DIST_APP_PATH/Contents/Frameworks" -name "*.framework" -type d | while read -r framework; do
  echo "Signing nested framework: $framework"
  codesign --force --sign "${SIGN_IDENTITY:--}" --timestamp=none "$framework"
done

# 2. Sign the main executable
echo "Signing main executable..."
codesign --force --sign "${SIGN_IDENTITY:--}" --timestamp=none "$DIST_APP_PATH/Contents/MacOS/$APP_NAME"

# 3. Finally sign the app bundle itself
echo "Signing app bundle..."
codesign --force --sign "${SIGN_IDENTITY:--}" --timestamp=none "$DIST_APP_PATH"

verify_bundle_signature "$DIST_APP_PATH"
validate_bundle_dependencies "$DIST_APP_PATH"

echo "Packaging DMG..."
DMG_VOLUME_NAME="$APP_NAME" "$ROOT_DIR/scripts/create-dmg.sh" "$DIST_APP_PATH" "$DIST_DMG_PATH"

echo "App bundle: $DIST_APP_PATH"
echo "DMG: $DIST_DMG_PATH"
