#!/usr/bin/env bash
# install.sh — Orb installer
#
# Downloads the latest (or specified) pre-built release from GitHub and installs it.
#
# Install targets:
#   --system       Install to /opt/orb + /usr/bin  (requires sudo, recommended)
#   --user         Install to ~/.local  (no sudo)
#
# Options:
#   --release=TAG  Install a specific release tag, e.g. --release=v0.1.0
#                  (defaults to latest)
#   --help
#
# Usage examples:
#   ./packaging/install.sh                    # interactive: choose target
#   ./packaging/install.sh --system           # system-wide, latest release
#   ./packaging/install.sh --user             # user-local, latest release
#   ./packaging/install.sh --release=v0.1.0 --system
#
# Requirements (runtime only — no build tools needed):
#   curl, python3, tar, zstd
#   gtk3, glib2, sqlite, systemd

set -euo pipefail

# ── Colors ────────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; MAGENTA='\033[0;35m'
BOLD='\033[1m'; NC='\033[0m'

log_step()  { echo -e "\n${BOLD}${MAGENTA}▶ $*${NC}"; }
log_info()  { echo -e "  ${GREEN}•${NC} $*"; }
log_warn()  { echo -e "  ${YELLOW}⚠ WARNING:${NC} $*"; }
log_error() { echo -e "  ${RED}✗ ERROR:${NC} $*" >&2; }
log_ok()    { echo -e "  ${GREEN}✓${NC} $*"; }
log_cmd()   { echo -e "  ${CYAN}\$${NC} $*"; }

# ── Constants ─────────────────────────────────────────────────────────────────
# All requests go through the official website proxy — no GitHub auth needed.
ORB_WEBSITE="https://orb.zerx.dev"

# When piped via `curl | bash`, BASH_SOURCE[0] is unset; fall back to a safe sentinel.
_script_src="${BASH_SOURCE[0]:-}"
if [[ -n "${_script_src}" ]]; then
    SCRIPT_DIR="$(cd "$(dirname "${_script_src}")" && pwd)"
else
    SCRIPT_DIR="<install script directory>"
fi

# ── Argument parsing ──────────────────────────────────────────────────────────
RELEASE_TAG=""   # empty = latest
PREFIX_MODE=""   # "system" | "user"

for arg in "$@"; do
    case "${arg}" in
        --release=*)  RELEASE_TAG="${arg#--release=}" ;;
        --system)     PREFIX_MODE="system" ;;
        --user)       PREFIX_MODE="user" ;;
        --help|-h)
            sed -n '2,/^[^#]/{ /^#/p }' "${BASH_SOURCE[0]}" | sed 's/^# \?//'
            exit 0
            ;;
        *)
            log_error "Unknown argument: ${arg}"
            echo "Usage: $0 [--release=TAG] [--system|--user] [--help]"
            exit 1
            ;;
    esac
done

# ── Banner ────────────────────────────────────────────────────────────────────
echo
echo -e "${BOLD}${MAGENTA}╔══════════════════════════════════════════╗${NC}"
echo -e "${BOLD}${MAGENTA}║        Orb Installer                     ║${NC}"
echo -e "${BOLD}${MAGENTA}╚══════════════════════════════════════════╝${NC}"
echo

# ── Interactive prefix selection ──────────────────────────────────────────────
if [[ -z "${PREFIX_MODE}" ]]; then
    echo -e "  Choose installation target:"
    echo -e "  ${BOLD}[1]${NC} System-wide  (/opt/orb, /usr/bin)  ${YELLOW}requires sudo${NC}"
    echo -e "  ${BOLD}[2]${NC} User-local   (~/.local)             ${GREEN}no sudo${NC}"
    echo
    # Read from /dev/tty so interactive prompts work even when stdin is a pipe
    # (e.g. `curl ... | bash`).
    read -rp "  Enter choice [1/2]: " choice </dev/tty
    case "${choice}" in
        1) PREFIX_MODE="system" ;;
        2) PREFIX_MODE="user" ;;
        *) log_error "Invalid choice"; exit 1 ;;
    esac
fi

# ── Derive install paths ──────────────────────────────────────────────────────
if [[ "${PREFIX_MODE}" == "system" ]]; then
    BUNDLE_DEST="/opt/orb"
    BIN_DIR="/usr/bin"
    SYSTEMD_UNIT_DIR="/usr/lib/systemd/user"
    UDEV_RULES_DIR="/usr/lib/udev/rules.d"
    DESKTOP_DIR="/usr/share/applications"
    ICON_BASE="/usr/share/icons/hicolor"
    NEED_SUDO=true
else
    BUNDLE_DEST="${HOME}/.local/share/orb"
    BIN_DIR="${HOME}/.local/bin"
    SYSTEMD_UNIT_DIR="${HOME}/.config/systemd/user"
    UDEV_RULES_DIR=""
    DESKTOP_DIR="${HOME}/.local/share/applications"
    ICON_BASE="${HOME}/.local/share/icons/hicolor"
    NEED_SUDO=false
fi

DAEMON_BIN="${BIN_DIR}/orb-daemon"
ORB_CLI="${BIN_DIR}/orb"

echo -e "  Install target : ${BOLD}${PREFIX_MODE}${NC}"
echo -e "  Bundle         : ${BUNDLE_DEST}"
echo -e "  CLI / daemon   : ${BIN_DIR}"
echo

# ── sudo helper ───────────────────────────────────────────────────────────────
_sudo() { ${NEED_SUDO} && sudo "$@" || "$@"; }

# ── Dependency check ──────────────────────────────────────────────────────────
check_deps() {
    log_step "Checking dependencies"
    local missing=()
    for cmd in curl python3 tar; do
        command -v "${cmd}" &>/dev/null && log_ok "${cmd}" || { log_warn "${cmd} not found"; missing+=("${cmd}"); }
    done
    # zstd: needed by tar --zstd (may be via libzstd in tar or standalone)
    if tar --zstd --version &>/dev/null 2>&1 || command -v zstd &>/dev/null; then
        log_ok "zstd (tar)"
    else
        log_warn "zstd not found (needed to extract .tar.zst)"
        missing+=("zstd")
    fi
    if [[ ${#missing[@]} -gt 0 ]]; then
        log_error "Missing tools: ${missing[*]}"
        echo -e "    ${CYAN}sudo pacman -S curl python zstd${NC}    # Arch"
        echo -e "    ${CYAN}sudo apt install curl python3 zstd${NC}  # Debian/Ubuntu"
        exit 1
    fi

    # Runtime library check (best-effort, warn only)
    local rt_ok=true
    for lib in libgtk-3.so.0 libglib-2.0.so.0 libsqlite3.so.0; do
        ldconfig -p 2>/dev/null | grep -q "${lib}" && log_ok "${lib}" || { log_warn "${lib} not in ldconfig cache"; rt_ok=false; }
    done
    if ! ${rt_ok}; then
        echo
        echo -e "  Install runtime deps:"
        echo -e "    ${CYAN}sudo pacman -S gtk3 glib2 sqlite${NC}                             # Arch"
        echo -e "    ${CYAN}sudo apt install libgtk-3-0 libglib2.0-0 libsqlite3-0${NC} # Debian/Ubuntu"
        echo
        read -rp "  Continue anyway? [y/N] " yn </dev/tty
        [[ "${yn,,}" == "y" ]] || exit 1
    fi
}

# ── Fetch release metadata via official website proxy ─────────────────────────
fetch_release_info() {
    local api_url="${ORB_WEBSITE}/api/latest-release"
    log_info "Fetching release info..."

    local json
    json="$(curl -fsSL --retry 3 "${api_url}")" || {
        log_error "Failed to reach ${api_url}. Check your internet connection."
        exit 1
    }

    RELEASE_VERSION="$(echo "${json}" | python3 -c "
import sys, json
d = json.load(sys.stdin)
if 'error' in d:
    print('ERROR: ' + d['error'], file=sys.stderr)
    sys.exit(1)
print(d['version'])
")" || {
        log_error "Could not parse release info — no release published yet?"
        exit 1
    }

    # If a specific tag was requested, validate it matches
    if [[ -n "${RELEASE_TAG}" ]]; then
        local requested_ver="${RELEASE_TAG#v}"
        if [[ "${RELEASE_VERSION}" != "${requested_ver}" ]]; then
            # Specific tag: build download URL directly for that tag
            RELEASE_TARBALL_URL="${ORB_WEBSITE}/api/download?tag=${RELEASE_TAG}"
            RELEASE_VERSION="${requested_ver}"
        else
            RELEASE_TARBALL_URL="$(echo "${json}" | python3 -c "import sys,json; print(json.load(sys.stdin)['tarball_url'])")"
        fi
    else
        RELEASE_TARBALL_URL="$(echo "${json}" | python3 -c "import sys,json; print(json.load(sys.stdin)['tarball_url'])")"
    fi

    # tarball_url from the API is a relative path (/api/download?...) — make it absolute
    if [[ "${RELEASE_TARBALL_URL}" == /* ]]; then
        RELEASE_TARBALL_URL="${ORB_WEBSITE}${RELEASE_TARBALL_URL}"
    fi

    # Checksum is served at /api/download?tag=...&checksum=1
    RELEASE_CHECKSUM_URL="${RELEASE_TARBALL_URL}&checksum=1"

    log_ok "Release: v${RELEASE_VERSION}"
    log_info "Download: ${RELEASE_TARBALL_URL}"
}

# ── Download and verify ───────────────────────────────────────────────────────
download_and_extract() {
    WORKDIR="$(mktemp -d)"

    # Use a fixed filename derived from the version (URL has query params, not a filename)
    local pkg_name="orb-${RELEASE_VERSION}-linux-x86_64.tar.zst"
    local tarball="${WORKDIR}/${pkg_name}"
    local checksum="${WORKDIR}/${pkg_name}.sha256"

    log_step "Downloading v${RELEASE_VERSION}"
    log_cmd "curl ... ${pkg_name}"
    curl -fL --retry 3 --progress-bar -o "${tarball}" "${RELEASE_TARBALL_URL}" || {
        log_error "Download failed."
        exit 1
    }
    log_ok "Downloaded: $(du -sh "${tarball}" | cut -f1)"

    # Download checksum and verify
    if curl -fsSL --retry 2 -o "${checksum}" "${RELEASE_CHECKSUM_URL}" 2>/dev/null; then
        log_step "Verifying checksum"
        # The checksum file references the original filename from the CI build.
        # Re-verify by computing the hash directly rather than relying on sha256sum -c
        # (which requires the filename inside the file to match exactly).
        local expected actual
        expected="$(awk '{print $1}' "${checksum}")"
        actual="$(sha256sum "${tarball}" | awk '{print $1}')"
        if [[ "${expected}" == "${actual}" ]]; then
            log_ok "Checksum OK"
        else
            log_error "Checksum mismatch — aborting."
            log_error "  expected: ${expected}"
            log_error "  actual:   ${actual}"
            exit 1
        fi
    else
        log_warn "Checksum unavailable — skipping verification"
    fi

    log_step "Extracting package"
    tar --zstd -xf "${tarball}" -C "${WORKDIR}"

    PKG_DIR="$(find "${WORKDIR}" -maxdepth 1 -type d -name "orb-*-linux-x86_64" | head -1)"
    [[ -n "${PKG_DIR}" ]] || { log_error "Unexpected tarball structure."; exit 1; }
    log_ok "Extracted: ${PKG_DIR}"
}

# ── Install steps ─────────────────────────────────────────────────────────────
install_bundle() {
    log_step "Installing Flutter bundle → ${BUNDLE_DEST}"
    _sudo mkdir -p "${BUNDLE_DEST}"
    _sudo cp -a "${PKG_DIR}/bundle/." "${BUNDLE_DEST}/"
    _sudo chmod 755 "${BUNDLE_DEST}/orb"
    log_ok "Bundle installed ($(du -sh "${PKG_DIR}/bundle" | cut -f1))"
}

install_daemon() {
    log_step "Installing orb-daemon → ${DAEMON_BIN}"
    _sudo mkdir -p "${BIN_DIR}"
    _sudo install -m755 "${PKG_DIR}/orb-daemon" "${DAEMON_BIN}"
    log_ok "orb-daemon installed"
}

install_cli_wrapper() {
    log_step "Installing CLI wrapper → ${ORB_CLI}"
    local wrapper="#!/bin/sh
# Orb CLI wrapper — LD_LIBRARY_PATH ensures dlopen() finds liborb_core.so
export LD_LIBRARY_PATH=\"${BUNDLE_DEST}/lib\${LD_LIBRARY_PATH:+:\$LD_LIBRARY_PATH}\"
exec ${BUNDLE_DEST}/orb \"\$@\"
"
    if ${NEED_SUDO}; then
        echo "${wrapper}" | sudo tee "${ORB_CLI}" > /dev/null
        sudo chmod 755 "${ORB_CLI}"
    else
        mkdir -p "${BIN_DIR}"
        echo "${wrapper}" > "${ORB_CLI}"
        chmod 755 "${ORB_CLI}"
    fi
    log_ok "CLI wrapper installed"

    if ! ${NEED_SUDO} && ! echo ":${PATH}:" | grep -q ":${BIN_DIR}:"; then
        log_warn "${BIN_DIR} is not in your PATH"
        echo -e "  Add to ~/.bashrc or ~/.zshrc:"
        echo -e "    ${CYAN}export PATH=\"\$HOME/.local/bin:\$PATH\"${NC}"
    fi
}

install_udev_rules() {
    local udev_src="${PKG_DIR}/70-orb-input.rules"

    if [[ -z "${UDEV_RULES_DIR}" ]]; then
        echo
        log_warn "udev rules require root — needed for global hotkeys."
        read -rp "  Install udev rules now with sudo? [Y/n] " yn </dev/tty
        if [[ "${yn,,}" != "n" ]]; then
            sudo install -Dm644 "${udev_src}" "/usr/lib/udev/rules.d/70-orb-input.rules"
            sudo udevadm control --reload-rules 2>/dev/null || true
            sudo udevadm trigger --subsystem-match=input 2>/dev/null || true
            log_ok "udev rules installed"
        else
            echo -e "  Install manually later:"
            log_cmd "sudo install -Dm644 <rules-file> /usr/lib/udev/rules.d/70-orb-input.rules"
            log_cmd "sudo udevadm control --reload-rules"
        fi
        return
    fi

    log_step "Installing udev rules → ${UDEV_RULES_DIR}/70-orb-input.rules"
    _sudo install -Dm644 "${udev_src}" "${UDEV_RULES_DIR}/70-orb-input.rules"
    _sudo udevadm control --reload-rules 2>/dev/null || true
    _sudo udevadm trigger --subsystem-match=input 2>/dev/null || true
    log_ok "udev rules installed"
}

install_desktop() {
    log_step "Installing .desktop entry and icons"
    _sudo mkdir -p "${DESKTOP_DIR}"

    local desktop="[Desktop Entry]
Type=Application
Name=Orb
Comment=Keyboard-first AI-native application launcher
Exec=${BUNDLE_DEST}/orb %u
Icon=orb
Categories=Utility;Application;
Keywords=launcher;search;run;apps;
StartupWMClass=dev.zerx.orb
StartupNotify=false
NoDisplay=false
X-OrbExecPath=${BUNDLE_DEST}/orb
"
    if ${NEED_SUDO}; then
        echo "${desktop}" | sudo tee "${DESKTOP_DIR}/orb.desktop" > /dev/null
    else
        echo "${desktop}" > "${DESKTOP_DIR}/orb.desktop"
    fi
    log_ok ".desktop → ${DESKTOP_DIR}/orb.desktop"

    local sizes=(16 32 48 64 128 256)
    for size in "${sizes[@]}"; do
        local src="${PKG_DIR}/icons/orb_logo_${size}.png"
        local dst_dir="${ICON_BASE}/${size}x${size}/apps"
        if [[ -f "${src}" ]]; then
            _sudo mkdir -p "${dst_dir}"
            _sudo cp -f "${src}" "${dst_dir}/orb.png"
        fi
    done

    command -v gtk-update-icon-cache &>/dev/null && \
        _sudo gtk-update-icon-cache -f -t "${ICON_BASE}" 2>/dev/null || true
    command -v update-desktop-database &>/dev/null && \
        _sudo update-desktop-database "${DESKTOP_DIR}" 2>/dev/null || true

    log_ok "Icons and .desktop installed"
}

install_service() {
    local svc_src="${PKG_DIR}/orb-daemon.service"

    log_step "Installing systemd user service → ${SYSTEMD_UNIT_DIR}/orb-daemon.service"
    _sudo mkdir -p "${SYSTEMD_UNIT_DIR}"

    # Remove any user-level override that would shadow the system unit.
    # ~/.config/systemd/user/ has higher priority than /usr/lib/systemd/user/,
    # so a stale dev-mode file there would keep loading instead of the freshly
    # installed one regardless of which SYSTEMD_UNIT_DIR we write to.
    local user_override="${HOME}/.config/systemd/user/orb-daemon.service"
    if [[ -f "${user_override}" ]]; then
        log_info "Removing stale user-level service override: ${user_override}"
        rm -f "${user_override}"
    fi

    if ${NEED_SUDO}; then
        sudo sed \
            -e "s|ExecStart=%h/.local/bin/orb-daemon|ExecStart=${DAEMON_BIN}|" \
            -e "/^\[Service\]/a Environment=ORB_BINARY=${BUNDLE_DEST}/orb" \
            -e "/^\[Service\]/a Environment=LD_LIBRARY_PATH=${BUNDLE_DEST}/lib" \
            "${svc_src}" \
            | sudo tee "${SYSTEMD_UNIT_DIR}/orb-daemon.service" > /dev/null
    else
        mkdir -p "${SYSTEMD_UNIT_DIR}"
        sed "/^\[Service\]/a Environment=ORB_BINARY=${BUNDLE_DEST}/orb" \
            "${svc_src}" \
            > "${SYSTEMD_UNIT_DIR}/orb-daemon.service"
    fi
    log_ok "Service file written"

    systemctl --user daemon-reload
    systemctl --user enable orb-daemon.service 2>/dev/null || true
    systemctl --user restart orb-daemon.service || true

    sleep 1
    if systemctl --user is-active --quiet orb-daemon.service; then
        local pid
        pid=$(systemctl --user show orb-daemon.service --property=MainPID --value 2>/dev/null || echo "?")
        log_ok "orb-daemon started (pid=${pid})"
    else
        log_warn "orb-daemon failed to start — check logs:"
        journalctl --user -u orb-daemon.service -n 15 --no-pager 2>&1 | sed 's/^/    /'
        log_warn "Retry with: systemctl --user start orb-daemon"
    fi
}

# ── Cleanup ───────────────────────────────────────────────────────────────────
cleanup() { [[ -n "${WORKDIR:-}" ]] && rm -rf "${WORKDIR}"; }

# ── Summary ───────────────────────────────────────────────────────────────────
print_summary() {
    echo
    echo -e "${BOLD}${GREEN}╔══════════════════════════════════════════╗${NC}"
    echo -e "${BOLD}${GREEN}║   Orb v${RELEASE_VERSION} installed!                 ║${NC}"
    echo -e "${BOLD}${GREEN}╚══════════════════════════════════════════╝${NC}"
    echo
    echo -e "  ${BOLD}Press Ctrl+Space to open Orb.${NC}"
    echo
    echo -e "  Useful commands:"
    echo -e "    ${CYAN}orb search firefox${NC}               # CLI search"
    echo -e "    ${CYAN}orb show${NC} / ${CYAN}orb hide${NC}               # show/hide window"
    echo -e "    ${CYAN}orb status${NC}                       # daemon status"
    echo -e "    ${CYAN}orb logs${NC}                         # tail log file"
    echo -e "    ${CYAN}systemctl --user status orb-daemon${NC}  # service status"
    echo
    echo -e "  To uninstall:"
    echo -e "    ${CYAN}${SCRIPT_DIR}/uninstall.sh${NC}"
    echo
}

# ── Main ──────────────────────────────────────────────────────────────────────
main() {
    trap cleanup EXIT

    check_deps
    fetch_release_info
    download_and_extract

    install_bundle
    install_daemon
    install_cli_wrapper
    install_udev_rules
    install_desktop
    install_service

    print_summary
}

main
