#!/usr/bin/env bash
# deploy.sh — Deploy Aether Native Launcher to onsite Mac laptops
#
# USAGE:
#   ./deploy.sh <num> [num ...]                       Deploy to one or more laptops (e.g. 03 04 05)
#   ./deploy.sh all                                    Deploy to all laptops in devices.conf
#   ./deploy.sh --seed-only <num>                      Update seed.json only — skip .app copy
#   ./deploy.sh --seed-only all
#   ./deploy.sh --build <num> [num ...]                Build first (npm run package:mac), then deploy
#   ./deploy.sh --build all
#   ./deploy.sh --fix-accessibility <num> [num ...]    Re-grant macOS Accessibility permission after .app update
#   ./deploy.sh --fix-accessibility all                (requires NOPASSWD sudo for sqlite3 — see README)
#
# REQUIRES:
#   event.env   — copy from event.env.example and fill in AETHER_API_KEY
#   builds/     — pre-built, or use --build to build before deploying
#
# SSH keys must already be installed on each target (run ssh-copy-id once per laptop).

set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEVICES_FILE="$SCRIPT_DIR/devices.conf"
EVENT_ENV="$SCRIPT_DIR/event.env"
SSH_USER="speaker ready"
BUILD_DIR="$SCRIPT_DIR/../builds"

# ── Argument parsing ──────────────────────────────────────────────────────────

SEED_ONLY=false
BUILD_FIRST=false
FIX_ACCESSIBILITY=false
TARGETS=()
# Bundle ID as embedded in Info.plist by electron-packager (no --app-bundle-id override)
BUNDLE_ID="com.electron.aetherlauncher"

usage() {
    grep '^#' "$0" | grep -v '^#!/' | sed 's/^# \{0,1\}//'
    exit 1
}

if [[ $# -eq 0 ]]; then usage; fi

while [[ $# -gt 0 ]]; do
    case "$1" in
        --seed-only)           SEED_ONLY=true ;;
        --build)               BUILD_FIRST=true ;;
        --fix-accessibility)   FIX_ACCESSIBILITY=true ;;
        --help|-h)             usage ;;
        all)         TARGETS+=("all") ;;
        *)           TARGETS+=("$1") ;;
    esac
    shift
done

if [[ ${#TARGETS[@]} -eq 0 ]]; then
    echo "ERROR: No targets specified."
    usage
fi

# ── Load event config ─────────────────────────────────────────────────────────

if [[ ! -f "$EVENT_ENV" ]]; then
    echo "ERROR: $EVENT_ENV not found."
    echo "  Copy event.env.example → event.env and fill in AETHER_API_KEY."
    exit 1
fi

# shellcheck source=/dev/null
source "$EVENT_ENV"

: "${AETHER_API_KEY:?event.env must set AETHER_API_KEY}"
: "${PRIMARY_API_BASE_URL:?event.env must set PRIMARY_API_BASE_URL}"
: "${BACKUP_API_BASE_URL:?event.env must set BACKUP_API_BASE_URL}"

# Render onsite URL as JSON null or quoted string
if [[ -n "${ONSITE_API_BASE_URL:-}" ]]; then
    ONSITE_JSON="\"$ONSITE_API_BASE_URL\""
else
    ONSITE_JSON="null"
fi

# ── Device list helpers ───────────────────────────────────────────────────────

# Returns "ip device_id" for a laptop number, or empty if not found
lookup_device() {
    local num="$1"
    grep -v '^[[:space:]]*#' "$DEVICES_FILE" \
        | grep -E "^[[:space:]]*${num}[[:space:]]" \
        | awk '{print $2, $3}' \
        | head -1
}

# Returns all laptop numbers from devices.conf (first column, non-comment lines)
all_device_nums() {
    grep -v '^[[:space:]]*#' "$DEVICES_FILE" \
        | grep -v '^[[:space:]]*$' \
        | awk '{print $1}'
}

# ── Deploy one laptop ─────────────────────────────────────────────────────────

deploy_laptop() {
    local num="$1"

    local info
    info=$(lookup_device "$num")
    if [[ -z "$info" ]]; then
        echo "  ERROR: Laptop $num not found in devices.conf"
        return 1
    fi

    local ip device_id
    ip=$(echo "$info" | awk '{print $1}')
    device_id=$(echo "$info" | awk '{print $2}')

    echo ""
    echo "══════════════════════════════════════════════"
    echo "  Laptop $num  ·  $ip  ·  $device_id"
    echo "══════════════════════════════════════════════"

    # ── Copy .app ──────────────────────────────────────────────────────────
    if [[ "$SEED_ONLY" != "true" ]]; then
        echo "  Detecting architecture..."
        local arch
        arch=$(ssh "$SSH_USER@$ip" "uname -m" 2>/dev/null) || {
            echo "  ERROR: SSH failed for $ip — is the laptop on the network?"
            return 1
        }

        local bundle
        case "$arch" in
            x86_64) bundle="$BUILD_DIR/aether_launcher-darwin-x64/aether_launcher.app" ;;
            arm64)  bundle="$BUILD_DIR/aether_launcher-darwin-arm64/aether_launcher.app" ;;
            *)
                echo "  ERROR: Unknown arch '$arch' on $ip"
                return 1
                ;;
        esac

        if [[ ! -d "$bundle" ]]; then
            echo "  ERROR: Build not found: $bundle"
            echo "         Run: npm run package:mac"
            return 1
        fi

        echo "  Arch: $arch → syncing $(basename "$bundle")..."
        # rsync --delete syncs contents in-place without removing the top-level .app dir.
        # This preserves the inode so macOS Aliases and Desktop shortcuts keep working.
        rsync -a --delete -e ssh "$bundle/" "$SSH_USER@$ip:/Applications/aether_launcher.app/" || {
            echo "  ERROR: rsync failed."
            return 1
        }
        echo "  .app synced."
    else
        echo "  (--seed-only: skipping .app copy)"
    fi

    # ── Write seed.json ────────────────────────────────────────────────────
    echo "  Writing seed.json..."
    ssh "$SSH_USER@$ip" "cat > ~/seed.json" <<EOF
{
  "event_device_id": "$device_id",
  "aether_api_key": "$AETHER_API_KEY",
  "primary_api_base_url": "$PRIMARY_API_BASE_URL",
  "backup_api_base_url": "$BACKUP_API_BASE_URL",
  "onsite_api_base_url": $ONSITE_JSON
}
EOF

    # ── Accessibility permission ───────────────────────────────────────────
    if [[ "$FIX_ACCESSIBILITY" == "true" ]]; then
        echo "  Resetting Accessibility permission (tccutil)..."
        if ssh "$SSH_USER@$ip" "tccutil reset Accessibility $BUNDLE_ID" 2>/dev/null; then
            echo "  tccutil reset OK."
        else
            echo "  WARNING: tccutil reset failed (non-fatal)."
        fi

        echo "  Granting Accessibility via TCC database (requires NOPASSWD sudo)..."
        # shellcheck disable=SC2016
        TCC_SQL="INSERT OR REPLACE INTO access(service,client,client_type,auth_value,auth_reason,auth_version) VALUES('kTCCServiceAccessibility','$BUNDLE_ID',0,2,4,1);"
        if ssh "$SSH_USER@$ip" "sudo sqlite3 '/Library/Application Support/com.apple.TCC/TCC.db' \"$TCC_SQL\"" 2>/dev/null; then
            echo "  ✓ Accessibility granted."
        else
            echo "  WARNING: TCC grant failed — manual re-authorization required."
            echo "           See README: macOS Accessibility Permission."
        fi
    fi

    # ── Verify ─────────────────────────────────────────────────────────────
    echo "  Verifying..."
    ssh "$SSH_USER@$ip" "cat ~/seed.json"
    if [[ "$SEED_ONLY" != "true" ]]; then
        ssh "$SSH_USER@$ip" \
            "test -d /Applications/aether_launcher.app && echo '  ✓ .app present' || echo '  ✗ .app NOT found'"
    fi

    echo "  ✓ Laptop $num done."
    return 0
}

# ── Build if requested ───────────────────────────────────────────────────────

if [[ "$BUILD_FIRST" == "true" ]]; then
    echo "══════════════════════════════════════════════"
    echo "  Building: npm run package:mac"
    echo "══════════════════════════════════════════════"
    (cd "$SCRIPT_DIR/.." && npm run package:mac) || {
        echo "ERROR: Build failed. Aborting deploy."
        exit 1
    }
    echo ""
fi

# ── Expand "all" target ───────────────────────────────────────────────────────

EXPANDED_TARGETS=()
for t in "${TARGETS[@]}"; do
    if [[ "$t" == "all" ]]; then
        while IFS= read -r num; do
            EXPANDED_TARGETS+=("$num")
        done < <(all_device_nums)
    else
        EXPANDED_TARGETS+=("$t")
    fi
done

# ── Run deploys ───────────────────────────────────────────────────────────────

FAILED=()
for num in "${EXPANDED_TARGETS[@]}"; do
    if ! deploy_laptop "$num"; then
        FAILED+=("$num")
    fi
done

echo ""
echo "══════════════════════════════════════════════"
if [[ ${#FAILED[@]} -eq 0 ]]; then
    echo "  All done. ✓"
else
    echo "  FAILED: ${FAILED[*]}"
    echo "  Re-run with just those numbers to retry."
    exit 1
fi
