#!/bin/bash
# XPyCode macOS .pkg Post-Install Script
# Runs as root after the payload has been laid down.
# Mirrors the logic of installer/windows/innosetup/xpycode_postinstall.bat
# and the Pascal CurStepChanged(ssPostInstall) block in xpycode.iss.

set -uo pipefail

INSTALL_DIR="/Applications/XPyCode"
PYTHON_DIR="${INSTALL_DIR}/python"
PYTHON_EXE="${PYTHON_DIR}/bin/python3"
PLIST_LABEL="com.xpycode.master"
LAUNCH_ARGS="--skip-manifest --log-level INFO"
INSTALLER_COMMON_DIR="/Applications/XPyCode"

echo "============================================================"
echo "  XPyCode Post-Install"
echo "============================================================"
echo "  Install dir : ${INSTALL_DIR}"
echo "  Python dir  : ${PYTHON_DIR}"
echo "============================================================"
echo ""

# ── Resolve the real user (not root) ─────────────────────────────────────────
if [ -n "${USER:-}" ] && [ "${USER}" != "root" ]; then
    REAL_USER="${USER}"
elif [ -n "${SUDO_USER:-}" ]; then
    REAL_USER="${SUDO_USER}"
else
    REAL_USER=$(stat -f "%Su" /dev/console 2>/dev/null || echo "")
fi

run_as_user() {
    if [ -n "${REAL_USER}" ] && [ "${REAL_USER}" != "root" ]; then
        sudo -u "${REAL_USER}" "$@"
    else
        "$@"
    fi
}

user_home() {
    if [ -n "${REAL_USER}" ] && [ "${REAL_USER}" != "root" ]; then
        eval echo "~${REAL_USER}"
    else
        echo "${HOME:-/var/root}"
    fi
}

USER_HOME=$(user_home)
echo "Real user : ${REAL_USER:-<unknown>}"
echo "User home : ${USER_HOME}"
echo ""

# ── Step 1: Detect architecture ───────────────────────────────────────────────
echo "[1/9] Detecting architecture..."
ARCH=$(uname -m)
if [ "${ARCH}" = "arm64" ]; then
    echo "  Architecture: Apple Silicon (arm64)"
else
    echo "  Architecture: Intel (x86_64)"
fi
echo ""

# ── Step 2: Create installation directory ─────────────────────────────────────
echo "[2/9] Creating installation directory..."
mkdir -p "${INSTALL_DIR}"
mkdir -p "${PYTHON_DIR}"
echo "  Created: ${INSTALL_DIR}"
echo ""

# ── Step 3: Install dedicated Python via official macOS .pkg ─────────────────
echo "[3/9] Installing dedicated Python..."

# The postinstall helper script copies the installer_common.py logic.
# We download the official Python macOS pkg and install the framework into
# PYTHON_DIR so the Python is fully isolated from the system.
PYTHON_VERSION="3.13.2"
PYTHON_PKG_URL="https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-macos11.pkg"
PYTHON_PKG_DOWNLOAD="/tmp/python-${PYTHON_VERSION}-macos11.pkg"

echo "  Downloading Python ${PYTHON_VERSION}..."
if curl -fsSL --retry 3 --retry-delay 5 -o "${PYTHON_PKG_DOWNLOAD}" "${PYTHON_PKG_URL}"; then
    echo "  Download complete: ${PYTHON_PKG_DOWNLOAD}"
else
    echo "  ERROR: Failed to download Python from ${PYTHON_PKG_URL}"
    exit 1
fi

echo "  Installing Python framework..."
# Install the pkg to a temporary location and then copy the framework to PYTHON_DIR
PYTHON_TMP_TARGET="/tmp/xpycode_python_install_$$"
mkdir -p "${PYTHON_TMP_TARGET}"

if installer -pkg "${PYTHON_PKG_DOWNLOAD}" -target "${PYTHON_TMP_TARGET}"; then
    echo "  Installer succeeded"

    # Locate the installed Python framework
    FRAMEWORK_PATH=$(find "${PYTHON_TMP_TARGET}" -type d -name "Python.framework" 2>/dev/null | head -1)
    if [ -z "${FRAMEWORK_PATH}" ]; then
        # Try standard location under /Library
        FRAMEWORK_PATH="${PYTHON_TMP_TARGET}/Library/Frameworks/Python.framework"
    fi

    if [ -d "${FRAMEWORK_PATH}" ]; then
        echo "  Copying Python framework to ${PYTHON_DIR}..."
        cp -R "${FRAMEWORK_PATH}" "${PYTHON_DIR}/"

        # Find the python3 binary inside the framework
        FRAMEWORK_PYTHON=$(find "${PYTHON_DIR}" -name "python3*" -type f 2>/dev/null | head -1)
        if [ -n "${FRAMEWORK_PYTHON}" ]; then
            # Create a simple bin/python3 symlink in PYTHON_DIR
            mkdir -p "${PYTHON_DIR}/bin"
            ln -sf "${FRAMEWORK_PYTHON}" "${PYTHON_EXE}" 2>/dev/null || cp "${FRAMEWORK_PYTHON}" "${PYTHON_EXE}"
            chmod 0755 "${PYTHON_EXE}"
            echo "  Python executable: ${PYTHON_EXE}"
        else
            echo "  WARNING: Could not find python3 binary in framework"
        fi
    else
        echo "  NOTE: Python.framework not found in tmp install; falling back to system Python"
    fi

    rm -rf "${PYTHON_TMP_TARGET}"
else
    echo "  NOTE: installer returned non-zero; attempting system Python fallback"
    rm -rf "${PYTHON_TMP_TARGET}"
fi

# Clean up downloaded pkg
rm -f "${PYTHON_PKG_DOWNLOAD}"

# Verify or fall back to system Python
if [ ! -x "${PYTHON_EXE}" ]; then
    echo "  Dedicated Python not available; trying system python3..."
    SYS_PYTHON=$(command -v python3 2>/dev/null || echo "")
    if [ -n "${SYS_PYTHON}" ]; then
        mkdir -p "${PYTHON_DIR}/bin"
        ln -sf "${SYS_PYTHON}" "${PYTHON_EXE}"
        chmod 0755 "${PYTHON_EXE}"
        echo "  Using system Python: ${SYS_PYTHON} -> ${PYTHON_EXE}"
    else
        echo "  ERROR: No Python 3 found. Installation cannot continue."
        exit 1
    fi
fi
echo ""

# ── Step 4: Upgrade pip + setuptools ─────────────────────────────────────────
echo "[4/9] Upgrading pip and setuptools..."
"${PYTHON_EXE}" -m pip install --upgrade --no-warn-script-location pip setuptools
echo ""

# ── Step 5: Install xpycode_master ────────────────────────────────────────────
echo "[5/9] Installing xpycode_master..."
"${PYTHON_EXE}" -m pip install --upgrade --no-warn-script-location xpycode_master
echo ""

# ── Step 6: Save Python executable path to service config ────────────────────
echo "[6/9] Saving service configuration..."
"${PYTHON_EXE}" -c "from xpycode_master.utils.start_config import set_python_exe; set_python_exe('${PYTHON_EXE}')" \
    && echo "  Python exe path saved" \
    || echo "  WARNING: Could not save service config"
echo ""

# ── Step 7: Register xpycode:// protocol handler ─────────────────────────────
echo "[7/9] Registering xpycode:// protocol handler..."
HANDLER_APP="${INSTALL_DIR}/XPyCodeHandler.app"
HANDLER_CONTENTS="${HANDLER_APP}/Contents"
HANDLER_MACOS="${HANDLER_CONTENTS}/MacOS"

mkdir -p "${HANDLER_MACOS}"

cat > "${HANDLER_CONTENTS}/Info.plist" << 'INFOPLIST'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleIdentifier</key>
    <string>com.xpycode.handler</string>
    <key>CFBundleName</key>
    <string>XPyCodeHandler</string>
    <key>CFBundleDisplayName</key>
    <string>XPyCode Protocol Handler</string>
    <key>CFBundleExecutable</key>
    <string>XPyCodeHandler</string>
    <key>CFBundleVersion</key>
    <string>1.0</string>
    <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleURLName</key>
            <string>XPyCode Protocol</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>xpycode</string>
            </array>
        </dict>
    </array>
    <key>LSMinimumSystemVersion</key>
    <string>10.15</string>
    <key>LSBackgroundOnly</key>
    <true/>
</dict>
</plist>
INFOPLIST

cat > "${HANDLER_MACOS}/XPyCodeHandler" << HANDLER
#!/bin/sh
exec "${PYTHON_EXE}" -m xpycode_master --from-protocol "\$1"
HANDLER

chmod 0755 "${HANDLER_MACOS}/XPyCodeHandler"

# Force-register with Launch Services
LSREGISTER="/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister"
if [ -x "${LSREGISTER}" ]; then
    run_as_user "${LSREGISTER}" -f "${HANDLER_APP}" \
        && echo "  Registered with Launch Services: ${HANDLER_APP}" \
        || echo "  WARNING: lsregister returned non-zero"
else
    echo "  NOTE: lsregister not found; Launch Services registration skipped"
fi
echo ""

# ── Step 8: Install launchd service (autostart at login) ─────────────────────
echo "[8/9] Installing launchd service..."
PLIST_DIR="${USER_HOME}/Library/LaunchAgents"
PLIST_PATH="${PLIST_DIR}/${PLIST_LABEL}.plist"
LOG_DIR="${USER_HOME}/.xpycode/logs"

run_as_user mkdir -p "${PLIST_DIR}"
run_as_user mkdir -p "${LOG_DIR}"

# Build service args from LAUNCH_ARGS variable
IFS=' ' read -ra ARGS_ARRAY <<< "${LAUNCH_ARGS}"
PLIST_PROGRAM_ARGS=""
for arg in "${ARGS_ARRAY[@]}"; do
    PLIST_PROGRAM_ARGS="${PLIST_PROGRAM_ARGS}
        <string>${arg}</string>"
done

cat > "${PLIST_PATH}" << PLIST
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>${PLIST_LABEL}</string>
    <key>ProgramArguments</key>
    <array>
        <string>${PYTHON_EXE}</string>
        <string>-m</string>
        <string>xpycode_master</string>${PLIST_PROGRAM_ARGS}
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>${LOG_DIR}/xpycode_service.log</string>
    <key>StandardErrorPath</key>
    <string>${LOG_DIR}/xpycode_service.log</string>
</dict>
</plist>
PLIST

chown "${REAL_USER:-root}" "${PLIST_PATH}" 2>/dev/null || true
chmod 0644 "${PLIST_PATH}"

# Load the service as the real user
run_as_user launchctl load "${PLIST_PATH}" \
    && echo "  Service loaded: ${PLIST_LABEL}" \
    || echo "  WARNING: launchctl load returned non-zero (service may already be loaded)"
echo ""

# ── Step 9: Create shortcuts and uninstaller ──────────────────────────────────
echo "[9/9] Creating shortcuts and uninstaller..."

# Desktop shortcut
DESKTOP_SHORTCUT="${USER_HOME}/Desktop/XPyCode.command"
cat > "${DESKTOP_SHORTCUT}" << SHORTCUT
#!/bin/bash
# XPyCode Launcher
"${PYTHON_EXE}" -m xpycode_master
SHORTCUT
chmod 0755 "${DESKTOP_SHORTCUT}"
chown "${REAL_USER:-root}" "${DESKTOP_SHORTCUT}" 2>/dev/null || true
echo "  Created desktop shortcut: ${DESKTOP_SHORTCUT}"

# Uninstaller
UNINSTALLER="${INSTALL_DIR}/Uninstall XPyCode.command"
cat > "${UNINSTALLER}" << UNINSTALL
#!/bin/bash
# XPyCode Uninstaller
set -euo pipefail

PLIST_LABEL="com.xpycode.master"
INSTALL_DIR="/Applications/XPyCode"
PLIST_PATH="\${HOME}/Library/LaunchAgents/\${PLIST_LABEL}.plist"
HANDLER_APP="\${INSTALL_DIR}/XPyCodeHandler.app"
HANDLER_APP_USER="\${HOME}/Applications/XPyCodeHandler.app"
DESKTOP_SHORTCUT="\${HOME}/Desktop/XPyCode.command"

echo "============================================================"
echo "  XPyCode Uninstaller"
echo "============================================================"
echo ""

read -r -p "Are you sure you want to uninstall XPyCode? [y/N]: " confirm
if [[ ! "\${confirm}" =~ ^[Yy]$ ]]; then
    echo "Uninstall cancelled."
    exit 0
fi

echo ""
echo "Uninstalling XPyCode..."
echo ""

echo "[1/6] Stopping XPyCode processes..."
pkill -f "xpycode_master" 2>/dev/null || true
sleep 1
echo "  Done"

echo "[2/6] Unloading launchd service..."
if [ -f "\${PLIST_PATH}" ]; then
    launchctl unload "\${PLIST_PATH}" 2>/dev/null || true
    echo "  Unloaded: \${PLIST_PATH}"
else
    echo "  Plist not found: \${PLIST_PATH}"
fi

echo "[3/6] Removing launchd plist..."
rm -f "\${PLIST_PATH}" && echo "  Removed: \${PLIST_PATH}" || true

echo "[4/6] Removing protocol handler..."
[ -d "\${HANDLER_APP}" ] && rm -rf "\${HANDLER_APP}" && echo "  Removed: \${HANDLER_APP}" || true
[ -d "\${HANDLER_APP_USER}" ] && rm -rf "\${HANDLER_APP_USER}" && echo "  Removed: \${HANDLER_APP_USER}" || true

echo "[5/6] Removing desktop shortcut..."
rm -f "\${DESKTOP_SHORTCUT}" && echo "  Removed: \${DESKTOP_SHORTCUT}" || true

echo "[6/6] Removing installation directory..."
if [ -d "\${INSTALL_DIR}" ]; then
    sudo rm -rf "\${INSTALL_DIR}" && echo "  Removed: \${INSTALL_DIR}" || echo "  WARNING: Could not remove \${INSTALL_DIR} (may need manual removal)"
fi

echo ""
echo "============================================================"
echo "  XPyCode has been uninstalled."
echo ""
echo "  User data directory (~/.xpycode) was NOT removed."
echo "  To remove all user data, run:  rm -rf ~/.xpycode"
echo "============================================================"
UNINSTALL

chmod 0755 "${UNINSTALLER}"
echo "  Created uninstaller: ${UNINSTALLER}"
echo ""

# ── Save start_config.json ───────────────────────────────────────────────────
echo "Saving install configuration..."
INSTALL_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

# Convert space-separated LAUNCH_ARGS to a JSON array
launch_args_to_json_array() {
    local args="$1"
    if [ -z "$args" ]; then
        echo "[]"
        return
    fi
    local json="["
    local first=1
    for token in $args; do
        # Escape backslashes then double-quotes for JSON string safety
        token=$(printf '%s' "$token" | sed 's/\\/\\\\/g; s/"/\\"/g')
        if [ $first -eq 1 ]; then
            json="${json}\"${token}\""
            first=0
        else
            json="${json},\"${token}\""
        fi
    done
    json="${json}]"
    echo "$json"
}

LAUNCH_ARGS_JSON=$(launch_args_to_json_array "${LAUNCH_ARGS}")

run_as_user mkdir -p "${USER_HOME}/.xpycode"
cat > "${USER_HOME}/.xpycode/start_config.json" << CONFIG
{
  "launch_args": ${LAUNCH_ARGS_JSON},
  "python_path": "${PYTHON_EXE}",
  "python_mode": "dedicated",
  "install_date": "${INSTALL_DATE}",
  "autostart": true,
  "desktop_shortcut": true,
  "platform": "macos",
  "install_dir": "${INSTALL_DIR}"
}
CONFIG
if [ -n "${REAL_USER}" ] && [ "${REAL_USER}" != "root" ]; then
    chown "${REAL_USER}" "${USER_HOME}/.xpycode/start_config.json" 2>/dev/null || true
fi
echo "  Saved: ${USER_HOME}/.xpycode/start_config.json"
echo ""

# ── Fix ownership of everything under INSTALL_DIR ────────────────────────────
echo "Setting ownership..."
if [ -n "${REAL_USER}" ] && [ "${REAL_USER}" != "root" ]; then
    chown -R "${REAL_USER}" "${INSTALL_DIR}" 2>/dev/null \
        && echo "  Owner: ${REAL_USER}" \
        || echo "  WARNING: chown failed (non-critical)"
fi
echo ""

echo "============================================================"
echo "  XPyCode Post-Install complete!"
echo "  XPyCode will start automatically at login."
echo "  Uninstaller: ${INSTALL_DIR}/Uninstall XPyCode.command"
echo "============================================================"
exit 0
