#!/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="--log-level INFO"

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 0: Configuration ─────────────────────────────────────────────────────
echo "[0/10] Collecting configuration..."
LOG_LEVEL=$(run_as_user osascript -e '
set logLevel to choose from list {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"} ¬
    with title "XPyCode Configuration" ¬
    with prompt "Select the log level:" ¬
    default items {"INFO"}
if logLevel is false then
    return "INFO"
else
    return item 1 of logLevel
end if
' 2>/dev/null || echo "INFO")

CREATE_LOG_FILE=$(run_as_user osascript -e '
set btn to button returned of (display dialog "Create a log file for XPyCode?" ¬
    with title "XPyCode Configuration" ¬
    buttons {"No", "Yes"} ¬
    default button "Yes")
return btn
' 2>/dev/null || echo "Yes")

CREATE_DESKTOP_SHORTCUT=$(run_as_user osascript -e '
set btn to button returned of (display dialog "Create a desktop shortcut?" ¬
    with title "XPyCode Configuration" ¬
    buttons {"No", "Yes"} ¬
    default button "Yes")
return btn
' 2>/dev/null || echo "Yes")

AUTOSTART=$(run_as_user osascript -e '
set btn to button returned of (display dialog "Start XPyCode automatically at login?" ¬
    with title "XPyCode Configuration" ¬
    buttons {"No", "Yes"} ¬
    default button "Yes")
return btn
' 2>/dev/null || echo "Yes")

LAUNCH_ARGS="--log-level ${LOG_LEVEL}"
if [ "${CREATE_LOG_FILE}" = "No" ]; then
    LAUNCH_ARGS="${LAUNCH_ARGS} --no-log-file"
fi
DESKTOP_SHORTCUT_ENABLED=true
if [ "${CREATE_DESKTOP_SHORTCUT}" = "No" ]; then
    DESKTOP_SHORTCUT_ENABLED=false
fi
AUTOSTART_ENABLED=true
if [ "${AUTOSTART}" = "No" ]; then
    AUTOSTART_ENABLED=false
fi

echo "  Log level        : ${LOG_LEVEL}"
echo "  Create log file  : ${CREATE_LOG_FILE}"
echo "  Desktop shortcut : ${CREATE_DESKTOP_SHORTCUT}"
echo "  Autostart        : ${AUTOSTART}"
echo "  Note: Manifest will be registered automatically (Microsoft Store not yet available)"
echo ""

# ── Step 1: Detect architecture ───────────────────────────────────────────────
echo "[1/10] 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/10] 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/10] 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 to root volume..."
# The macOS installer CLI requires -target to be a volume mount point (like /).
# The official python.org .pkg installs to /Library/Frameworks/Python.framework/.
PYTHON_MINOR_VERSION=$(echo "${PYTHON_VERSION}" | cut -d. -f1-2)
FRAMEWORK_SRC="/Library/Frameworks/Python.framework/Versions/${PYTHON_MINOR_VERSION}"
PYTHON_MODE="dedicated"

if installer -pkg "${PYTHON_PKG_DOWNLOAD}" -target /; then
    echo "  Installer succeeded"
else
    echo "  NOTE: installer returned non-zero; will attempt to use framework if already present"
fi

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

# Copy the installed framework into our isolated PYTHON_DIR
if [ -d "${FRAMEWORK_SRC}" ]; then
    echo "  Copying Python framework to ${PYTHON_DIR}..."
    mkdir -p "${PYTHON_DIR}"
    cp -R "${FRAMEWORK_SRC}" "${PYTHON_DIR}/Python.framework_${PYTHON_MINOR_VERSION}"

    # Create bin/ symlinks pointing into our copied framework
    mkdir -p "${PYTHON_DIR}/bin"
    FRAMEWORK_PYTHON="${PYTHON_DIR}/Python.framework_${PYTHON_MINOR_VERSION}/bin/python${PYTHON_MINOR_VERSION}"
    if [ -x "${FRAMEWORK_PYTHON}" ]; then
        ln -sf "${FRAMEWORK_PYTHON}" "${PYTHON_EXE}"
        chmod 0755 "${PYTHON_EXE}"
        echo "  Python executable: ${PYTHON_EXE} -> ${FRAMEWORK_PYTHON}"
    else
        echo "  WARNING: Could not find python${PYTHON_MINOR_VERSION} binary in copied framework"
    fi

    # Ensure pip is available (the framework install includes it)
    if [ -x "${PYTHON_EXE}" ] && ! "${PYTHON_EXE}" -m pip --version >/dev/null 2>&1; then
        echo "  Running ensurepip to bootstrap pip..."
        "${PYTHON_EXE}" -m ensurepip --upgrade 2>/dev/null || true
    fi
else
    echo "  NOTE: Framework not found at ${FRAMEWORK_SRC}; falling back to system Python"
fi

# 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}"
        PYTHON_MODE="system"
        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/10] Upgrading pip and setuptools..."
"${PYTHON_EXE}" -m pip install --upgrade --no-warn-script-location pip setuptools
echo ""

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

# ── Step 6: Register SSL certificates ─────────────────────────────────────────
echo "[6/10] Registering SSL certificates..."
run_as_user "${PYTHON_EXE}" -c "from xpycode_master.addin_launcher.certificate_manager import CertificateManager; CertificateManager().ensure_certificates()" \
    && echo "  SSL certificates registered" \
    || echo "  WARNING: Could not register SSL certificates - they will be generated on first run"
echo ""

# ── Step 7: Save Python executable path to service config ────────────────────
echo "[7/10] 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 8: Register xpycode:// protocol handler ─────────────────────────────
echo "[8/10] 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 9: Install launchd service (autostart at login) ─────────────────────
echo "[9/10] Installing launchd service..."
if [ "${AUTOSTART_ENABLED}" = "true" ]; then
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 (use modern bootstrap API, fall back to legacy)
REAL_USER_ID=$(id -u "${REAL_USER}" 2>/dev/null || echo "")
if [ -n "${REAL_USER_ID}" ]; then
    launchctl bootstrap "gui/${REAL_USER_ID}" "${PLIST_PATH}" 2>/dev/null \
        || run_as_user launchctl load "${PLIST_PATH}" 2>/dev/null \
        || echo "  WARNING: Could not load service (may need manual start)"
    echo "  Service loaded: ${PLIST_LABEL}"
else
    run_as_user launchctl load "${PLIST_PATH}" 2>/dev/null || true
fi
else
    echo "  Autostart at login skipped (user choice)"
fi
echo ""

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

# Desktop shortcut
DESKTOP_SHORTCUT="${USER_HOME}/Desktop/XPyCode.command"
if [ "${DESKTOP_SHORTCUT_ENABLED}" = "true" ]; then
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}"
else
    echo "  Desktop shortcut creation skipped (user choice)"
fi

# 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
    CURRENT_UID=\$(id -u)
    launchctl bootout "gui/\${CURRENT_UID}/\${PLIST_LABEL}" 2>/dev/null \
        || 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": "${PYTHON_MODE}",
  "install_date": "${INSTALL_DATE}",
  "autostart": ${AUTOSTART_ENABLED},
  "desktop_shortcut": ${DESKTOP_SHORTCUT_ENABLED},
  "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
