#!/bin/bash

set -Eeuo pipefail

# ============================================================
# Phoenix AWR Installer for macOS
# ============================================================

APP_NAME="Phoenix AWR"
BUNDLE_ID="cl.mc3d.phoenixawr"
URL_SCHEME="phoenixawr"

URL_VIEWER="https://www.mc3d.cl/documents/d/guest/applet_viewer_by_mc3d"
URL_RUNTIME="https://www.mc3d.cl/documents/d/guest/zulu21-44-17-ca-fx-jre21-0-8-macosx_x64-tar"

BASE="$HOME/Library/Application Support/PhoenixApplet"

APPLICATION_DIR="$BASE/application"
RUNTIME_DIR="$BASE/runtime"
BIN_DIR="$BASE/bin"
LOG_DIR="$BASE/logs"

JAR="$APPLICATION_DIR/PhoenixAppletViewer.jar"
JVM_CONF="$BASE/jvm.conf"
LAUNCHER="$BIN_DIR/phoenixawr"

USER_APPLICATIONS_DIR="$HOME/Applications"
APP_BUNDLE="$USER_APPLICATIONS_DIR/Phoenix AWR.app"

DESKTOP_APP="$HOME/Desktop/Phoenix AWR.app"
OLD_DESKTOP_LINK="$HOME/Desktop/PhoenixAWR"

INSTALL_LOG="$LOG_DIR/phoenix-installer.log"
STARTUP_LOG="$LOG_DIR/phoenixawr-startup.log"
PROTOCOL_LOG="$LOG_DIR/phoenixawr-protocol.log"

TEMP_DIR="${TMPDIR:-/tmp}/phoenixawr-installer-$$"

VIEWER_ZIP="$TEMP_DIR/PhoenixViewer.zip"
RUNTIME_ARCHIVE="$TEMP_DIR/PhoenixRuntime.tar.gz"
VIEWER_EXTRACT_DIR="$TEMP_DIR/viewer"

LSREGISTER="/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister"

# ============================================================
# Native Messaging antiguo
# ============================================================

OLD_NATIVE_HOST_FILES=(
    "phoenixappletrunner.json"
    "phoenixawr.json"
    "cl.mc3d.phoenixawr.json"
    "cl.mc3d.phoenixappletrunner.json"
)

NATIVE_MESSAGING_DIRS=(
    "$HOME/Library/Application Support/Mozilla/NativeMessagingHosts"
    "$HOME/Library/Application Support/Google/Chrome/NativeMessagingHosts"
    "$HOME/Library/Application Support/Google/Chrome Beta/NativeMessagingHosts"
    "$HOME/Library/Application Support/Google/Chrome Canary/NativeMessagingHosts"
    "$HOME/Library/Application Support/Chromium/NativeMessagingHosts"
    "$HOME/Library/Application Support/Microsoft Edge/NativeMessagingHosts"
    "$HOME/Library/Application Support/Microsoft Edge Beta/NativeMessagingHosts"
    "$HOME/Library/Application Support/Microsoft Edge Dev/NativeMessagingHosts"
    "$HOME/Library/Application Support/BraveSoftware/Brave-Browser/NativeMessagingHosts"
    "$HOME/Library/Application Support/Vivaldi/NativeMessagingHosts"
    "$HOME/Library/Application Support/com.operasoftware.Opera/NativeMessagingHosts"
)

# ============================================================
# Funciones
# ============================================================

log() {
    local message="$1"

    printf '%s\n' "$message"

    if [ -d "$LOG_DIR" ]; then
        printf '[%s] %s\n' \
            "$(date '+%Y-%m-%d %H:%M:%S')" \
            "$message" >> "$INSTALL_LOG"
    fi
}

fail() {
    log "[ERROR] $1"
    exit 1
}

command_exists() {
    command -v "$1" >/dev/null 2>&1
}

remove_path() {
    local path="$1"

    if [ -e "$path" ] || [ -L "$path" ]; then
        rm -rf "$path"
        log "[INFO] Removed: $path"
    fi
}

cleanup() {
    rm -rf "$TEMP_DIR"
}

handle_error() {
    local exit_code=$?
    local line_number="${1:-unknown}"

    log "[ERROR] Installation failed at line $line_number."
    exit "$exit_code"
}

trap cleanup EXIT
trap 'handle_error $LINENO' ERR

download_file() {
    local url="$1"
    local destination="$2"

    rm -f "$destination"

    if command_exists curl; then
        curl \
            --fail \
            --location \
            --show-error \
            --connect-timeout 30 \
            --retry 3 \
            --retry-delay 2 \
            --output "$destination" \
            "$url"

    elif command_exists wget; then
        wget \
            --tries=3 \
            --timeout=30 \
            --output-document="$destination" \
            "$url"

    else
        fail "curl or wget is required."
    fi

    if [ ! -s "$destination" ]; then
        fail "Downloaded file is empty: $destination"
    fi
}

remove_native_messaging() {
    local directory
    local filename

    log "[INFO] Removing obsolete Native Messaging registrations..."

    for directory in "${NATIVE_MESSAGING_DIRS[@]}"; do
        for filename in "${OLD_NATIVE_HOST_FILES[@]}"; do
            remove_path "$directory/$filename"
        done
    done
}

reset_tcc_permission() {
    local service="$1"

    if command_exists tccutil; then
        tccutil reset "$service" "$BUNDLE_ID" >/dev/null 2>&1 || true
    fi
}

# ============================================================
# Validaciones
# ============================================================

if [ "$(uname -s)" != "Darwin" ]; then
    printf '%s\n' "[ERROR] This installer supports macOS only."
    exit 1
fi

ARCH="$(uname -m)"

case "$ARCH" in
    x86_64)
        printf '%s\n' "[INFO] Intel Mac detected."
        ;;

    arm64)
        printf '%s\n' "[INFO] Apple Silicon detected."
        printf '%s\n' "[INFO] The current Phoenix runtime is x86_64."
        printf '%s\n' "[INFO] Rosetta 2 is required."
        ;;

    *)
        printf '%s\n' "[ERROR] Unsupported architecture: $ARCH"
        exit 1
        ;;
esac

command_exists curl ||
command_exists wget ||
    fail "curl or wget is required."

command_exists tar ||
    fail "tar is required."

command_exists unzip ||
    fail "unzip is required."

command_exists osacompile ||
    fail "osacompile is required."

mkdir -p "$TEMP_DIR"

echo
echo "============================================================"
echo " Phoenix AWR Installer for macOS"
echo "============================================================"
echo

# ============================================================
# Desregistrar aplicación anterior
# ============================================================

if [ -x "$LSREGISTER" ]; then
    if [ -d "$APP_BUNDLE" ]; then
        "$LSREGISTER" -u "$APP_BUNDLE" >/dev/null 2>&1 || true
    fi

    if [ -d "/Applications/Phoenix AWR.app" ]; then
        "$LSREGISTER" -u "/Applications/Phoenix AWR.app" \
            >/dev/null 2>&1 || true
    fi
fi

# ============================================================
# Eliminar instalaciones anteriores
# ============================================================

remove_path "$APP_BUNDLE"
remove_path "$DESKTOP_APP"
remove_path "$OLD_DESKTOP_LINK"

if [ -e "/Applications/Phoenix AWR.app" ]; then
    if [ -w "/Applications" ]; then
        remove_path "/Applications/Phoenix AWR.app"
    else
        printf '%s\n' \
            "[WARNING] /Applications/Phoenix AWR.app could not be removed."
    fi
fi

remove_native_messaging

remove_path "$BASE"

mkdir -p "$APPLICATION_DIR"
mkdir -p "$RUNTIME_DIR"
mkdir -p "$BIN_DIR"
mkdir -p "$LOG_DIR"
mkdir -p "$USER_APPLICATIONS_DIR"
mkdir -p "$VIEWER_EXTRACT_DIR"

touch "$INSTALL_LOG"

# ============================================================
# Descargar runtime oficial
# ============================================================

log "[INFO] Downloading Phoenix AWR Java runtime..."

download_file \
    "$URL_RUNTIME" \
    "$RUNTIME_ARCHIVE"

if ! tar -tzf "$RUNTIME_ARCHIVE" >/dev/null 2>&1; then
    fail "The runtime archive is invalid."
fi

tar -xzf "$RUNTIME_ARCHIVE" -C "$RUNTIME_DIR"

JAVA_EXECUTABLE="$(
    find "$RUNTIME_DIR" \
        -type f \
        -path '*/bin/java' \
        2>/dev/null |
        head -n 1
)"

if [ -z "$JAVA_EXECUTABLE" ]; then
    fail "Java was not found in the downloaded runtime."
fi

chmod 755 "$JAVA_EXECUTABLE"

JAVA_BIN_DIR="$(dirname "$JAVA_EXECUTABLE")"
JAVA_HOME="$(dirname "$JAVA_BIN_DIR")"

if [ ! -x "$JAVA_HOME/bin/java" ]; then
    fail "The Phoenix AWR Java runtime is not executable."
fi

if [ "$ARCH" = "arm64" ]; then
    if ! /usr/bin/arch -x86_64 \
        "$JAVA_HOME/bin/java" \
        -version >/dev/null 2>&1; then

        fail "Rosetta 2 is required. Install it with:

softwareupdate --install-rosetta --agree-to-license"
    fi
else
    "$JAVA_HOME/bin/java" -version >/dev/null 2>&1 ||
        fail "The Phoenix AWR Java runtime could not start."
fi

# ============================================================
# Configuración del runtime
# ============================================================

cat > "$JVM_CONF" <<EOF
runtime_mode=bundled
runtime_vendor=MC3D
runtime_architecture=x86_64
runtime_includes_javafx=true
java_home=$JAVA_HOME
EOF

chmod 644 "$JVM_CONF"

# ============================================================
# Descargar Phoenix AWR
# ============================================================

log "[INFO] Downloading Phoenix AWR..."

download_file \
    "$URL_VIEWER" \
    "$VIEWER_ZIP"

if ! unzip -tq "$VIEWER_ZIP" >/dev/null 2>&1; then
    fail "Phoenix AWR download is not a valid ZIP."
fi

unzip -q -o \
    "$VIEWER_ZIP" \
    -d "$VIEWER_EXTRACT_DIR"

DOWNLOADED_JAR="$(
    find "$VIEWER_EXTRACT_DIR" \
        -type f \
        -iname 'PhoenixAppletViewer.jar' \
        2>/dev/null |
        head -n 1
)"

if [ -z "$DOWNLOADED_JAR" ]; then
    fail "PhoenixAppletViewer.jar was not found."
fi

cp -f "$DOWNLOADED_JAR" "$JAR"
chmod 644 "$JAR"

# ============================================================
# No instalar Native Messaging
# ============================================================

log "[INFO] Removing Native Messaging files from package..."

find "$VIEWER_EXTRACT_DIR" \
    -type f \
    \( \
        -iname 'phoenixappletrunner*.json' \
        -o -iname 'phoenixawr*.json' \
        -o -iname 'register_plugin*.sh' \
        -o -iname 'register_native*.sh' \
        -o -iname 'phoenixappletrunner.sh' \
        -o -iname '*native*messaging*.sh' \
    \) \
    -delete 2>/dev/null || true

# ============================================================
# Crear launcher
# ============================================================

cat > "$LAUNCHER" <<'LAUNCHER_EOF'
#!/bin/bash

set -Eeuo pipefail

BASE="$HOME/Library/Application Support/PhoenixApplet"
JVM_CONF="$BASE/jvm.conf"
JAR="$BASE/application/PhoenixAppletViewer.jar"
LOG_DIR="$BASE/logs"
LOG_FILE="$LOG_DIR/phoenixawr-protocol.log"

mkdir -p "$LOG_DIR"

show_error() {
    local message="$1"

    printf '[%s] ERROR: %s\n' \
        "$(date '+%Y-%m-%d %H:%M:%S')" \
        "$message" >> "$LOG_FILE"

    /usr/bin/osascript \
        -e "display dialog \"${message//\"/\\\"}\" buttons {\"OK\"} default button \"OK\" with icon stop with title \"Phoenix AWR\"" \
        >/dev/null 2>&1 || true
}

if [ ! -f "$JVM_CONF" ]; then
    show_error "Phoenix AWR runtime configuration was not found."
    exit 1
fi

JAVA_HOME="$(
    sed -n \
        's/^[[:space:]]*java_home[[:space:]]*=[[:space:]]*//p' \
        "$JVM_CONF" |
        head -n 1
)"

JAVA_BIN="$JAVA_HOME/bin/java"

if [ ! -x "$JAVA_BIN" ]; then
    show_error "Phoenix AWR Java runtime was not found."
    exit 1
fi

if [ ! -f "$JAR" ]; then
    show_error "PhoenixAppletViewer.jar was not found."
    exit 1
fi

ARGUMENT="${1:-}"
SYSTEM_ARCH="$(uname -m)"

JAVA_COMMAND=("$JAVA_BIN")

if [ "$SYSTEM_ARCH" = "arm64" ]; then
    JAVA_COMMAND=(/usr/bin/arch -x86_64 "$JAVA_BIN")
fi

if [ -z "$ARGUMENT" ]; then
    exec "${JAVA_COMMAND[@]}" \
        -jar "$JAR"
fi

exec "${JAVA_COMMAND[@]}" \
    -jar "$JAR" \
    "$ARGUMENT"
LAUNCHER_EOF

chmod 755 "$LAUNCHER"

# ============================================================
# Crear aplicación macOS
# ============================================================

APPLESCRIPT_SOURCE="$TEMP_DIR/PhoenixAWR.applescript"

ESCAPED_LAUNCHER="$(
    printf '%s' "$LAUNCHER" |
        sed 's/\\/\\\\/g; s/"/\\"/g'
)"

ESCAPED_STARTUP_LOG="$(
    printf '%s' "$STARTUP_LOG" |
        sed 's/\\/\\\\/g; s/"/\\"/g'
)"

cat > "$APPLESCRIPT_SOURCE" <<EOF
on run
    startPhoenix("")
end run

on open location theURL
    startPhoenix(theURL)
end open location

on startPhoenix(theArgument)
    set launcherPath to "$ESCAPED_LAUNCHER"
    set startupLog to "$ESCAPED_STARTUP_LOG"

    if theArgument is "" then
        set shellCommand to quoted form of launcherPath & " >> " & quoted form of startupLog & " 2>&1 &"
    else
        set shellCommand to quoted form of launcherPath & " " & quoted form of theArgument & " >> " & quoted form of startupLog & " 2>&1 &"
    end if

    do shell script shellCommand
end startPhoenix
EOF

osacompile \
    -o "$APP_BUNDLE" \
    "$APPLESCRIPT_SOURCE"

PLIST="$APP_BUNDLE/Contents/Info.plist"

# ============================================================
# Identidad del bundle
# ============================================================

/usr/libexec/PlistBuddy \
    -c "Set :CFBundleName $APP_NAME" \
    "$PLIST" 2>/dev/null ||
/usr/libexec/PlistBuddy \
    -c "Add :CFBundleName string $APP_NAME" \
    "$PLIST"

/usr/libexec/PlistBuddy \
    -c "Set :CFBundleDisplayName $APP_NAME" \
    "$PLIST" 2>/dev/null ||
/usr/libexec/PlistBuddy \
    -c "Add :CFBundleDisplayName string $APP_NAME" \
    "$PLIST"

/usr/libexec/PlistBuddy \
    -c "Set :CFBundleIdentifier $BUNDLE_ID" \
    "$PLIST" 2>/dev/null ||
/usr/libexec/PlistBuddy \
    -c "Add :CFBundleIdentifier string $BUNDLE_ID" \
    "$PLIST"

/usr/libexec/PlistBuddy \
    -c "Set :CFBundleShortVersionString 1.0" \
    "$PLIST" 2>/dev/null ||
/usr/libexec/PlistBuddy \
    -c "Add :CFBundleShortVersionString string 1.0" \
    "$PLIST"

/usr/libexec/PlistBuddy \
    -c "Set :CFBundleVersion 1" \
    "$PLIST" 2>/dev/null ||
/usr/libexec/PlistBuddy \
    -c "Add :CFBundleVersion string 1" \
    "$PLIST"

/usr/libexec/PlistBuddy \
    -c "Set :NSHighResolutionCapable true" \
    "$PLIST" 2>/dev/null ||
/usr/libexec/PlistBuddy \
    -c "Add :NSHighResolutionCapable bool true" \
    "$PLIST"

# ============================================================
# Declaraciones de permisos de macOS
# ============================================================

set_plist_string() {
    local key="$1"
    local value="$2"

    /usr/libexec/PlistBuddy \
        -c "Delete :$key" \
        "$PLIST" 2>/dev/null || true

    /usr/libexec/PlistBuddy \
        -c "Add :$key string $value" \
        "$PLIST"
}

set_plist_string \
    "NSMicrophoneUsageDescription" \
    "Phoenix AWR necesita acceder al micrófono cuando una aplicación Java solicita grabar audio."

set_plist_string \
    "NSDesktopFolderUsageDescription" \
    "Phoenix AWR necesita acceder a los archivos que el usuario seleccione en el Escritorio."

set_plist_string \
    "NSDocumentsFolderUsageDescription" \
    "Phoenix AWR necesita acceder a los archivos que el usuario seleccione en Documentos."

set_plist_string \
    "NSDownloadsFolderUsageDescription" \
    "Phoenix AWR necesita acceder a los archivos que el usuario seleccione en Descargas."

set_plist_string \
    "NSRemovableVolumesUsageDescription" \
    "Phoenix AWR necesita acceder a los archivos seleccionados en unidades externas."

set_plist_string \
    "NSNetworkVolumesUsageDescription" \
    "Phoenix AWR necesita acceder a los archivos seleccionados en unidades de red."

# Descripciones adicionales para futuras capacidades.
set_plist_string \
    "NSCameraUsageDescription" \
    "Phoenix AWR necesita acceder a la cámara cuando una aplicación Java solicita capturar imágenes o video."

set_plist_string \
    "NSLocationUsageDescription" \
    "Phoenix AWR necesita acceder a la ubicación cuando una aplicación Java solicita utilizarla."

# ============================================================
# Registrar protocolo phoenixawr:
# ============================================================

/usr/libexec/PlistBuddy \
    -c "Delete :CFBundleURLTypes" \
    "$PLIST" 2>/dev/null || true

/usr/libexec/PlistBuddy \
    -c "Add :CFBundleURLTypes array" \
    "$PLIST"

/usr/libexec/PlistBuddy \
    -c "Add :CFBundleURLTypes:0 dict" \
    "$PLIST"

/usr/libexec/PlistBuddy \
    -c "Add :CFBundleURLTypes:0:CFBundleURLName string $BUNDLE_ID" \
    "$PLIST"

/usr/libexec/PlistBuddy \
    -c "Add :CFBundleURLTypes:0:CFBundleURLSchemes array" \
    "$PLIST"

/usr/libexec/PlistBuddy \
    -c "Add :CFBundleURLTypes:0:CFBundleURLSchemes:0 string $URL_SCHEME" \
    "$PLIST"

/usr/libexec/PlistBuddy \
    -c "Add :CFBundleURLTypes:0:CFBundleTypeRole string Viewer" \
    "$PLIST"

# ============================================================
# Validar Info.plist
# ============================================================

plutil -lint "$PLIST" ||
    fail "Phoenix AWR Info.plist is invalid."

log "[INFO] Privacy declarations added to Info.plist."

# ============================================================
# Firma ad-hoc
# ============================================================

if command_exists codesign; then
    codesign \
        --force \
        --deep \
        --sign - \
        "$APP_BUNDLE" >/dev/null 2>&1 || true

    log "[INFO] Phoenix AWR.app signed with an ad-hoc signature."
fi

# ============================================================
# Registrar aplicación
# ============================================================

if [ ! -x "$LSREGISTER" ]; then
    fail "LaunchServices registration tool was not found."
fi

"$LSREGISTER" \
    -f \
    "$APP_BUNDLE"

# ============================================================
# Reiniciar decisiones de privacidad anteriores
# ============================================================

log "[INFO] Resetting previous macOS privacy decisions..."

reset_tcc_permission "Microphone"
reset_tcc_permission "Camera"
reset_tcc_permission "SystemPolicyDesktopFolder"
reset_tcc_permission "SystemPolicyDocumentsFolder"
reset_tcc_permission "SystemPolicyDownloadsFolder"
reset_tcc_permission "SystemPolicyRemovableVolumes"
reset_tcc_permission "SystemPolicyNetworkVolumes"

# ============================================================
# Crear acceso en Escritorio
# ============================================================

remove_path "$DESKTOP_APP"

ln -s \
    "$APP_BUNDLE" \
    "$DESKTOP_APP"

log "[INFO] Desktop shortcut created."

# ============================================================
# Resultado
# ============================================================

echo
echo "============================================================"
echo " Phoenix AWR installed successfully"
echo "============================================================"
echo
echo "Application:"
echo "  $APP_BUNDLE"
echo
echo "Runtime:"
echo "  $JAVA_HOME"
echo
echo "Native Messaging:"
echo "  Removed"
echo
echo "Registered protocol:"
echo "  phoenixawr:"
echo
echo "Privacy declarations:"
echo "  Microphone"
echo "  Camera"
echo "  Desktop"
echo "  Documents"
echo "  Downloads"
echo "  External volumes"
echo "  Network volumes"
echo
echo "Protocol test:"
echo "  open 'phoenixawr:https://www.mc3d.cl/'"
echo
echo "Important:"
echo "  macOS should request microphone permission when an applet"
echo "  tries to open the microphone for the first time."
echo

open "$APP_BUNDLE"

exit 0