#!/bin/bash

# ============================================
#   Navigator Code v1.0.0 — Установка для Ubuntu
# ============================================
#
# Использование:
#   chmod +x install-ubuntu.sh
#   ./install-ubuntu.sh
#
# Что делает:
#   1. Проверяет/устанавливает Node.js 20+
#   2. Копирует приложение в ~/.local/share/navigator/
#   3. Создаёт команды navicode, navigator, nav в ~/.local/bin/
#   4. Добавляет ~/.local/bin в PATH (если нужно)

set -euo pipefail

# ============================================
# Цвета
# ============================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NC='\033[0m'

info()    { echo -e "${BLUE}  ℹ  ${NC}$1"; }
ok()      { echo -e "${GREEN}  ✓  ${NC}$1"; }
warn()    { echo -e "${YELLOW}  ⚠  ${NC}$1"; }
err()     { echo -e "${RED}  ✗  ${NC}$1"; }

# ============================================
# Переменные
# ============================================
APP_NAME="navigator"
APP_VERSION="1.0.0"
INSTALL_DIR="${HOME}/.local/share/${APP_NAME}"
BIN_DIR="${HOME}/.local/bin"
NODE_VERSION="20"
NODE_FULL_VERSION="20.18.1"

# Определяем архитектуру
ARCH=$(uname -m)
case "${ARCH}" in
    x86_64)  NODE_ARCH="x64";   RG_ARCH="x64-linux" ;;
    aarch64) NODE_ARCH="arm64"; RG_ARCH="arm64-linux" ;;
    *)
        err "Неподдерживаемая архитектура: ${ARCH}"
        err "Поддерживаются: x86_64 (amd64), aarch64 (arm64)"
        exit 1
        ;;
esac

# ============================================
# Заголовок
# ============================================
echo ""
echo -e "${BOLD}============================================${NC}"
echo -e "${BOLD}  Navigator Code v${APP_VERSION} — Установка${NC}"
echo -e "${BOLD}============================================${NC}"
echo ""
info "Система: $(lsb_release -ds 2>/dev/null || cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d '\"' || uname -s)"
info "Архитектура: ${ARCH} (${NODE_ARCH})"
info "Каталог установки: ${INSTALL_DIR}"
echo ""

# ============================================
# Определяем директорию скрипта (где лежат файлы дистрибутива)
# ============================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Проверяем, что app/dist/cli.js существует рядом со скриптом
if [[ ! -f "${SCRIPT_DIR}/app/dist/cli.js" ]]; then
    err "Не найден файл app/dist/cli.js рядом со скриптом"
    err "Убедитесь, что скрипт находится в корне дистрибутива Navigator Code"
    exit 1
fi

# ============================================
# Определение версии glibc
# ============================================
GLIBC_STR="unknown"
NEED_UNOFFICIAL=false

if command -v ldd &>/dev/null; then
    GLIBC_STR=$(ldd --version 2>&1 | head -1 | sed 's/.*\s\([0-9]*\.[0-9]*\).*/\1/' || echo "0.0")
    GLIBC_MAJOR=$(echo "${GLIBC_STR}" | cut -d. -f1 | tr -cd '0-9')
    GLIBC_MINOR=$(echo "${GLIBC_STR}" | cut -d. -f2 | tr -cd '0-9')
    GLIBC_MAJOR=${GLIBC_MAJOR:-0}
    GLIBC_MINOR=${GLIBC_MINOR:-0}

    if [ "${GLIBC_MAJOR}" -lt 2 ] 2>/dev/null || \
       { [ "${GLIBC_MAJOR}" -eq 2 ] && [ "${GLIBC_MINOR}" -lt 28 ]; } 2>/dev/null; then
        warn "glibc ${GLIBC_STR} (< 2.28 — потребуется unofficial-builds Node.js)"
        NEED_UNOFFICIAL=true
    else
        ok "glibc ${GLIBC_STR}"
    fi
else
    warn "ldd не найден — не удалось определить версию glibc"
fi

# ============================================
# Проверка Node.js
# ============================================
check_node() {
    # Сначала проверяем портативный Node.js из предыдущей установки
    local node_dir="${INSTALL_DIR}/node"
    if [[ -x "${node_dir}/bin/node" ]]; then
        if "${node_dir}/bin/node" -e "process.exit(0)" 2>/dev/null; then
            local ver
            ver=$("${node_dir}/bin/node" -v | sed 's/v//' | cut -d. -f1)
            if [[ "${ver}" -ge 18 ]]; then
                ok "Портативный Node.js $("${node_dir}/bin/node" -v) уже установлен"
                NODE_BIN="${node_dir}/bin/node"
                return 0
            else
                warn "Портативный Node.js $("${node_dir}/bin/node" -v) устарел (нужен >= 18), переустанавливаем..."
                rm -rf "${node_dir}"
            fi
        else
            warn "Портативный Node.js не запускается, переустанавливаем..."
            rm -rf "${node_dir}"
        fi
    fi

    # Проверяем системный Node.js
    if command -v node &>/dev/null; then
        if node -e "process.exit(0)" 2>/dev/null; then
            local ver
            ver=$(node -v | sed 's/v//' | cut -d. -f1)
            if [[ "${ver}" -ge 18 ]]; then
                ok "Node.js $(node -v) уже установлен"
                NODE_BIN="$(command -v node)"
                return 0
            else
                warn "Node.js $(node -v) устарел (нужен >= 18)"
                return 1
            fi
        else
            warn "Node.js $(node -v) установлен, но не запускается (несовместимость glibc)"
            return 1
        fi
    fi
    return 1
}

# ============================================
# Скачивание файла (curl или wget)
# ============================================
download_file() {
    local url="$1"
    local dest="$2"
    local timeout=60

    if command -v curl &>/dev/null; then
        curl -fSL --progress-bar --connect-timeout 15 --max-time ${timeout} "${url}" -o "${dest}"
    elif command -v wget &>/dev/null; then
        wget --show-progress --timeout=15 --tries=2 "${url}" -O "${dest}"
    else
        err "Не найден curl или wget. Установите: sudo apt install curl"
        exit 1
    fi
}

# ============================================
# Установка Node.js через snap (fallback для старых glibc)
# ============================================
install_node_via_snap() {
    if ! command -v snap &>/dev/null; then
        warn "snap не установлен, пробуем nvm..."
        install_node_via_nvm
        return
    fi

    info "Установка Node.js 20 через snap..."
    info "Потребуется пароль sudo:"

    if ! sudo snap install node --classic --channel=20; then
        warn "snap install не удался, пробуем nvm..."
        install_node_via_nvm
        return
    fi

    # snap может установить node в разные места
    local snap_node=""
    for candidate in /snap/bin/node /snap/node/current/bin/node; do
        if [[ -x "${candidate}" ]]; then
            snap_node="${candidate}"
            break
        fi
    done

    # Также проверяем через which (snap добавляет в PATH)
    if [[ -z "${snap_node}" ]]; then
        snap_node=$(which node 2>/dev/null || true)
    fi

    if [[ -z "${snap_node}" ]]; then
        warn "snap установил node, но бинарник не найден"
        warn "Пробуем nvm..."
        install_node_via_nvm
        return
    fi

    # Проверяем что запускается
    local test_output
    test_output=$("${snap_node}" -e "console.log('OK')" 2>&1) || true
    if [[ "${test_output}" == "OK" ]]; then
        NODE_BIN="${snap_node}"
        ok "Node.js $("${snap_node}" -v) установлен через snap (${snap_node})"
        return 0
    else
        warn "snap node не запускается: ${test_output}"
        warn "Пробуем nvm..."
        install_node_via_nvm
        return
    fi
}

# ============================================
# Установка Node.js через nvm (компилирует из исходников если нужно)
# ============================================
install_node_via_nvm() {
    info "Установка nvm..."

    export NVM_DIR="${INSTALL_DIR}/nvm"
    mkdir -p "${NVM_DIR}"

    if command -v curl &>/dev/null; then
        curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | PROFILE=/dev/null bash
    elif command -v wget &>/dev/null; then
        wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | PROFILE=/dev/null bash
    else
        err "Не удалось установить nvm (нужен curl или wget)"
        exit 1
    fi

    # Загружаем nvm
    [ -s "${NVM_DIR}/nvm.sh" ] && . "${NVM_DIR}/nvm.sh"

    if ! command -v nvm &>/dev/null; then
        err "nvm не удалось инициализировать"
        show_manual_install_help
        exit 1
    fi

    info "Установка Node.js 20 через nvm..."
    if nvm install 20; then
        NODE_BIN=$(nvm which 20 2>/dev/null || true)

        # nvm which может не работать, ищем бинарник вручную
        if [[ -z "${NODE_BIN}" ]] || [[ ! -x "${NODE_BIN}" ]]; then
            NODE_BIN=$(find "${NVM_DIR}/versions/node" -name "node" -type f 2>/dev/null | head -1 || true)
        fi

        if [[ -n "${NODE_BIN}" ]] && [[ -x "${NODE_BIN}" ]]; then
            local test_output
            test_output=$("${NODE_BIN}" -e "console.log('OK')" 2>&1) || true
            if [[ "${test_output}" == "OK" ]]; then
                ok "Node.js $("${NODE_BIN}" -v) установлен через nvm (${NODE_BIN})"
                return 0
            else
                warn "nvm node не запускается: ${test_output}"
            fi
        fi
    fi

    err "Не удалось установить Node.js ни одним способом"
    err ""
    show_manual_install_help
    exit 1
}

# ============================================
# Справка по ручной установке
# ============================================
show_manual_install_help() {
    err "Ваша система: glibc ${GLIBC_STR}"
    err ""
    err "Варианты решения:"
    err ""
    err "  1. Обновите ОС до Ubuntu 20.04+ или Debian 10+ (рекомендуется)"
    err ""
    err "  2. Установите Node.js 18+ вручную через snap:"
    err "     sudo snap install node --classic --channel=20"
    err "     Затем запустите этот скрипт повторно."
    err ""
    err "  3. Установите Node.js 18+ вручную через nvm:"
    err "     curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash"
    err "     source ~/.bashrc"
    err "     nvm install 20"
    err "     Затем запустите этот скрипт повторно."
}

# ============================================
# Установка Node.js (портативная копия)
# ============================================
install_node_portable() {
    local node_dir="${INSTALL_DIR}/node"

    # Очистка старой установки (если check_node не удалил)
    if [[ -d "${node_dir}" ]]; then
        rm -rf "${node_dir}"
    fi

    # Проверяем встроенный Node.js в дистрибутиве (каталог node/)
    if [[ -d "${SCRIPT_DIR}/node" ]] && [[ -x "${SCRIPT_DIR}/node/bin/node" ]]; then
        if "${SCRIPT_DIR}/node/bin/node" -e "process.exit(0)" 2>/dev/null; then
            info "Копирование встроенного Node.js из дистрибутива..."
            mkdir -p "${node_dir}"
            cp -r "${SCRIPT_DIR}/node/"* "${node_dir}/"
            chmod +x "${node_dir}/bin/node"
            NODE_BIN="${node_dir}/bin/node"
            ok "Node.js скопирован: $("${NODE_BIN}" -v)"
            return 0
        else
            warn "Встроенный Node.js несовместим с этой системой"
        fi
    fi

    # Встроенный fallback: node-fallback.tar.gz (glibc 2.17+, без интернета)
    if [[ -f "${SCRIPT_DIR}/node-fallback.tar.gz" ]]; then
        info "Установка встроенного Node.js (glibc 2.17+)..."
        mkdir -p "${node_dir}"
        if tar -xzf "${SCRIPT_DIR}/node-fallback.tar.gz" -C "${node_dir}" --strip-components=1; then
            NODE_BIN="${node_dir}/bin/node"
            chmod +x "${NODE_BIN}"
            if "${NODE_BIN}" -e "process.exit(0)" 2>/dev/null; then
                ok "Node.js $("${NODE_BIN}" -v) установлен из встроенного архива"
                return 0
            else
                warn "Встроенный Node.js (fallback) не запускается на glibc ${GLIBC_STR}"
                rm -rf "${node_dir}"
            fi
        else
            warn "Ошибка распаковки node-fallback.tar.gz"
            rm -rf "${node_dir}"
        fi
    fi

    # Формируем список URL для попыток скачивания
    # Приложение требует Node.js 18+ (ESM, node:readline/promises)
    local urls=()

    if [[ "${NEED_UNOFFICIAL}" == "true" ]]; then
        # glibc < 2.28: unofficial-builds (glibc 2.17+), формат .tar.gz (не требует xz-utils)
        urls+=(
            "https://unofficial-builds.nodejs.org/download/release/v${NODE_FULL_VERSION}/node-v${NODE_FULL_VERSION}-linux-${NODE_ARCH}-glibc-217.tar.gz"
            "https://unofficial-builds.nodejs.org/download/release/v18.20.4/node-v18.20.4-linux-${NODE_ARCH}-glibc-217.tar.gz"
        )
    else
        # glibc >= 2.28: официальные сборки
        urls+=(
            "https://nodejs.org/dist/v${NODE_FULL_VERSION}/node-v${NODE_FULL_VERSION}-linux-${NODE_ARCH}.tar.gz"
            "https://nodejs.org/dist/v18.20.4/node-v18.20.4-linux-${NODE_ARCH}.tar.gz"
        )
    fi

    local tmp_file
    tmp_file=$(mktemp /tmp/node-XXXXXX.tar.gz)

    for url in "${urls[@]}"; do
        # Извлекаем версию из URL для логов
        local try_ver
        try_ver=$(echo "${url}" | sed 's/.*node-v\([0-9.]*\)-.*/\1/')
        local is_unofficial=""
        if echo "${url}" | grep -q "unofficial"; then
            is_unofficial=" (unofficial-builds, glibc 2.17+)"
        fi

        info "Попытка: Node.js v${try_ver}${is_unofficial}"
        info "URL: ${url}"

        if download_file "${url}" "${tmp_file}"; then
            local fsize
            fsize=$(ls -lh "${tmp_file}" 2>/dev/null | awk '{print $5}')
            ok "Скачано (${fsize})"

            info "Распаковка..."
            rm -rf "${node_dir}"
            mkdir -p "${node_dir}"
            if tar -xzf "${tmp_file}" -C "${node_dir}" --strip-components=1; then
                ok "Распаковано"
            else
                warn "Ошибка распаковки tar.gz"
                rm -rf "${node_dir}"
                continue
            fi

            NODE_BIN="${node_dir}/bin/node"
            if [[ ! -f "${NODE_BIN}" ]]; then
                warn "Файл ${NODE_BIN} не найден после распаковки"
                rm -rf "${node_dir}"
                continue
            fi
            chmod +x "${NODE_BIN}"

            info "Проверка запуска..."
            local run_output
            run_output=$("${NODE_BIN}" -e "console.log('OK')" 2>&1) || true
            if [[ "${run_output}" == "OK" ]]; then
                rm -f "${tmp_file}"
                local installed_ver
                installed_ver=$("${NODE_BIN}" -v)
                ok "Node.js ${installed_ver} работает!"
                if [[ "${try_ver}" != "${NODE_FULL_VERSION}" ]]; then
                    warn "Установлена совместимая версия ${installed_ver} (вместо v${NODE_FULL_VERSION}) из-за ограничений glibc ${GLIBC_STR}"
                fi
                return 0
            else
                warn "Node.js v${try_ver} не запускается на glibc ${GLIBC_STR}:"
                warn "${run_output}"
                rm -rf "${node_dir}"
            fi
        else
            warn "Не удалось скачать: $(basename "${url}")"
        fi
        echo ""
    done

    rm -f "${tmp_file}"
    warn "Бинарные сборки Node.js не совместимы с glibc ${GLIBC_STR}"

    err ""
    err "Node.js 18+ требует glibc >= 2.28"
    err "Ваша система: glibc ${GLIBC_STR} ($(lsb_release -ds 2>/dev/null || cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d '\"'))"
    err ""
    err "Решение: обновите ОС до Ubuntu 20.04+ или Debian 10+"
    err ""
    err "  sudo do-release-upgrade"
    err ""
    exit 1
}

# ============================================
# Установка приложения
# ============================================
install_app() {
    info "Установка Navigator Code..."

    # Создаём каталоги
    mkdir -p "${INSTALL_DIR}/app/dist"
    mkdir -p "${INSTALL_DIR}/app/webapp/public"

    # Копируем приложение (CLI + Web GUI + зависимости)
    cp -r "${SCRIPT_DIR}/app/dist/"* "${INSTALL_DIR}/app/dist/"
    cp "${SCRIPT_DIR}/app/package.json" "${INSTALL_DIR}/app/" 2>/dev/null || true
    cp -r "${SCRIPT_DIR}/app/webapp/"* "${INSTALL_DIR}/app/webapp/" 2>/dev/null || true
    if [[ -d "${SCRIPT_DIR}/app/node_modules" ]]; then
        mkdir -p "${INSTALL_DIR}/app/node_modules"
        cp -r "${SCRIPT_DIR}/app/node_modules/"* "${INSTALL_DIR}/app/node_modules/"
    fi

    ok "Приложение установлено в ${INSTALL_DIR}/app/"
}

# ============================================
# Создание лаунчеров (CLI + Web GUI)
# ============================================
create_launcher() {
    mkdir -p "${BIN_DIR}"

    # --- CLI лаунчер: navicode (основная команда) ---
    cat > "${BIN_DIR}/navicode" <<LAUNCHER
#!/bin/bash
# Navigator Code v${APP_VERSION} — CLI лаунчер
# Установлен: $(date '+%Y-%m-%d %H:%M')

NODE_BIN="${NODE_BIN}"
APP="${INSTALL_DIR}/app/dist/cli.js"

# Если портативный Node.js удалён, пробуем системный
if [[ ! -x "\${NODE_BIN}" ]]; then
    NODE_BIN=\$(command -v node 2>/dev/null || true)
    if [[ -z "\${NODE_BIN}" ]]; then
        echo "Ошибка: Node.js не найден."
        echo "Установите: sudo apt install nodejs"
        echo "Или переустановите Navigator Code: ~/.local/share/navigator/install-ubuntu.sh"
        exit 1
    fi
fi

exec "\${NODE_BIN}" "\${APP}" "\$@"
LAUNCHER

    chmod +x "${BIN_DIR}/navicode"

    # Алиасы: navigator, nav — копии navicode
    cp "${BIN_DIR}/navicode" "${BIN_DIR}/navigator"
    cp "${BIN_DIR}/navicode" "${BIN_DIR}/nav"
    chmod +x "${BIN_DIR}/navigator" "${BIN_DIR}/nav"
    ok "Команды 'navicode', 'navigator', 'nav' созданы в ${BIN_DIR}/"

    # --- Web GUI лаунчер: navigator-web ---
    # Поддерживает аргумент — путь к проекту (для контекстного меню проводника)
    # Пытается открыть Chromium-подобный браузер в --app режиме (окно без вкладок/адресной строки)
    cat > "${BIN_DIR}/navigator-web" <<LAUNCHER
#!/bin/bash
# Navigator Code v${APP_VERSION} — Web GUI лаунчер
# Использование:
#   navigator-web                 # открыть домашнюю папку
#   navigator-web /path/to/proj   # открыть конкретный каталог
# Окно: если найден Chrome/Chromium/Edge/Brave — открывается в app-режиме (без браузерного UI).

NODE_BIN="${NODE_BIN}"
SERVER="${INSTALL_DIR}/app/webapp/server.js"
PORT=\${NAVIGATOR_PORT:-3100}

if [[ ! -x "\${NODE_BIN}" ]]; then
    NODE_BIN=\$(command -v node 2>/dev/null || true)
    if [[ -z "\${NODE_BIN}" ]]; then
        echo "Ошибка: Node.js не найден."
        echo "Установите: sudo apt install nodejs"
        exit 1
    fi
fi

# Каталог проекта (первый аргумент или \$PWD, если это не домашний каталог)
TARGET_PATH="\${1:-}"
if [[ -z "\${TARGET_PATH}" ]] && [[ "\${PWD}" != "\${HOME}" ]]; then
    TARGET_PATH="\${PWD}"
fi

# Кодируем путь для URL
urlencode() {
    local s="\$1" out="" c i
    for (( i=0; i<\${#s}; i++ )); do
        c="\${s:i:1}"
        case "\$c" in
            [a-zA-Z0-9._~/-]) out+="\$c" ;;
            *) printf -v c '%%%02X' "'\$c"; out+="\$c" ;;
        esac
    done
    printf '%s' "\$out"
}
URL="http://localhost:\${PORT}/?app=1"
if [[ -n "\${TARGET_PATH}" ]]; then
    URL="\${URL}&path=\$(urlencode "\${TARGET_PATH}")"
fi

echo ""
echo "  Navigator Code Web Interface"
echo "  URL: \${URL}"
echo ""

# Ищем Chromium-подобный браузер для app-режима
APP_BROWSER=""
for b in google-chrome google-chrome-stable chromium chromium-browser microsoft-edge microsoft-edge-stable brave-browser vivaldi; do
    if command -v "\$b" &>/dev/null; then
        APP_BROWSER="\$b"
        break
    fi
done

open_browser() {
    sleep 1
    if [[ -n "\${APP_BROWSER}" ]]; then
        "\${APP_BROWSER}" --app="\${URL}" --new-window &>/dev/null &
    elif command -v xdg-open &>/dev/null; then
        xdg-open "\${URL}" &>/dev/null &
    fi
}
open_browser &

exec "\${NODE_BIN}" "\${SERVER}"
LAUNCHER

    chmod +x "${BIN_DIR}/navigator-web"
    ok "Команда 'navigator-web' создана в ${BIN_DIR}/"
}

# ============================================
# Создание ярлыков в меню приложений (.desktop)
# ============================================
create_desktop_entries() {
    local desktop_dir="${HOME}/.local/share/applications"
    mkdir -p "${desktop_dir}"

    # Копируем иконку
    local icon_path="${INSTALL_DIR}/icon.png"
    if [[ -f "${SCRIPT_DIR}/icon.png" ]]; then
        cp "${SCRIPT_DIR}/icon.png" "${icon_path}"
    fi

    # --- CLI: открывает терминал с navicode ---
    cat > "${desktop_dir}/navigator-cli.desktop" <<DESKTOP
[Desktop Entry]
Name=Navigator Code (CLI)
Comment=AI-агент для разработки — терминал
Exec=${BIN_DIR}/navicode
Icon=${icon_path}
Terminal=true
Type=Application
Categories=Development;IDE;
Keywords=navigator;navicode;ai;code;cli;
StartupNotify=false
DESKTOP

    chmod +x "${desktop_dir}/navigator-cli.desktop"

    # --- Web GUI: запускает сервер и открывает браузер ---
    cat > "${desktop_dir}/navigator-web.desktop" <<DESKTOP
[Desktop Entry]
Name=Navigator Code (Web GUI)
Comment=AI-агент для разработки — веб-интерфейс
Exec=${BIN_DIR}/navigator-web
Icon=${icon_path}
Terminal=false
Type=Application
Categories=Development;IDE;
Keywords=navigator;ai;code;web;gui;
StartupNotify=true
DESKTOP

    chmod +x "${desktop_dir}/navigator-web.desktop"

    # Обновляем кэш .desktop файлов (если доступно)
    if command -v update-desktop-database &>/dev/null; then
        update-desktop-database "${desktop_dir}" 2>/dev/null || true
    fi

    ok "Ярлыки созданы в меню приложений"
}

# ============================================
# Контекстное меню проводников Linux
# ============================================
# Один bash-сниппет работает в Nautilus/Nemo/Caja (разные env-переменные URI).
write_fm_script() {
    local path="$1"
    cat > "${path}" <<FMSCRIPT
#!/usr/bin/env bash
URI="\${NAUTILUS_SCRIPT_CURRENT_URI:-\${NEMO_SCRIPT_CURRENT_URI:-\${CAJA_SCRIPT_CURRENT_URI:-}}}"
if [[ "\${URI}" == file://* ]]; then
    URI="\${URI#file://}"
    URI="\$(printf '%b' "\${URI//%/\\\\x}")"
fi
TARGET="\${URI:-\${1:-\$PWD}}"
exec "${BIN_DIR}/navigator-web" "\${TARGET}"
FMSCRIPT
    chmod +x "${path}"
}

create_filemanager_integration() {
    local icon_path="${INSTALL_DIR}/icon.png"
    # ASCII-имя — чтобы работало в любых локалях (Unity, старая Ubuntu)
    local script_name="Open in Navigator Code"

    # 1. Nautilus (GNOME Files, Ubuntu Unity, Ubuntu default)
    local nautilus_scripts="${HOME}/.local/share/nautilus/scripts"
    mkdir -p "${nautilus_scripts}"
    write_fm_script "${nautilus_scripts}/${script_name}"
    ok "Nautilus: скрипт «${script_name}»"

    # 1b. FileManager-Actions (fma) — пункт в корневом меню, работает и на
    # пустом пространстве каталога (Background).
    local fma_dir="${HOME}/.local/share/file-manager/actions"
    mkdir -p "${fma_dir}"
    cat > "${fma_dir}/navigator-code.desktop" <<FMA
[Desktop Entry]
Type=Action
Name=Open in Navigator Code
Name[ru]=Открыть в Navigator Code
Icon=${icon_path}
Profiles=profile-folder;profile-background;

[X-Action-Profile profile-folder]
MimeTypes=inode/directory;
Exec=${BIN_DIR}/navigator-web %d
SelectionCount=>0

[X-Action-Profile profile-background]
MimeTypes=inode/directory;
Exec=${BIN_DIR}/navigator-web %d
SelectionCount==0
FMA
    ok "FileManager-Actions: действие «Open in Navigator Code»"

    # 2. Nemo (Cinnamon / Linux Mint)
    local nemo_scripts="${HOME}/.local/share/nemo/scripts"
    mkdir -p "${nemo_scripts}"
    write_fm_script "${nemo_scripts}/${script_name}"
    local nemo_actions="${HOME}/.local/share/nemo/actions"
    mkdir -p "${nemo_actions}"
    cat > "${nemo_actions}/navigator-code.nemo_action" <<NEMOACT
[Nemo Action]
Name=Open in Navigator Code
Name[ru]=Открыть в Navigator Code
Comment=Open Navigator Code in this directory
Exec=${BIN_DIR}/navigator-web %d
Icon-Name=${icon_path}
Selection=Any
Extensions=dir;
EscapeSpaces=true
NEMOACT
    ok "Nemo: скрипт и nemo-action"

    # 3. Caja (MATE)
    local caja_scripts="${HOME}/.config/caja/scripts"
    mkdir -p "${caja_scripts}"
    write_fm_script "${caja_scripts}/${script_name}"
    ok "Caja: скрипт «${script_name}»"

    # 4. Dolphin / Konqueror (KDE)
    local kde_service_dir="${HOME}/.local/share/kio/servicemenus"
    mkdir -p "${kde_service_dir}"
    cat > "${kde_service_dir}/navigator-code.desktop" <<DOLPHIN
[Desktop Entry]
Type=Service
ServiceTypes=KonqPopupMenu/Plugin
MimeType=inode/directory;
Actions=openNavigator;
X-KDE-Priority=TopLevel

[Desktop Action openNavigator]
Name=Open in Navigator Code
Name[ru]=Открыть в Navigator Code
Icon=${icon_path}
Exec=${BIN_DIR}/navigator-web %d
DOLPHIN
    chmod +x "${kde_service_dir}/navigator-code.desktop" 2>/dev/null || true
    ok "Dolphin: пункт «Открыть в Navigator Code»"

    # 5. Thunar (Xfce) — uca.xml программно
    local thunar_dir="${HOME}/.config/Thunar"
    local uca="${thunar_dir}/uca.xml"
    mkdir -p "${thunar_dir}"
    local uid="navigator-code-$(date +%s)"
    local action_xml="  <action>
    <icon>${icon_path}</icon>
    <name>Open in Navigator Code</name>
    <unique-id>${uid}</unique-id>
    <command>${BIN_DIR}/navigator-web %d</command>
    <description>Open Navigator Code in this directory</description>
    <patterns>*</patterns>
    <directories/>
  </action>
</actions>"
    if [[ -f "${uca}" ]]; then
        if ! grep -q "navigator-web" "${uca}" 2>/dev/null; then
            python3 - "${uca}" "${action_xml}" <<'PYUCA' 2>/dev/null || true
import sys, io
path, payload = sys.argv[1], sys.argv[2]
with io.open(path, 'r', encoding='utf-8') as f:
    data = f.read()
if '</actions>' in data:
    data = data.replace('</actions>', payload)
    with io.open(path, 'w', encoding='utf-8') as f:
        f.write(data)
PYUCA
        fi
    else
        cat > "${uca}" <<UCA
<?xml version="1.0" encoding="UTF-8"?>
<actions>
${action_xml}
UCA
    fi
    ok "Thunar: особое действие «Open in Navigator Code»"

    # Перезапуск файл-менеджеров — чтобы пункты появились без logout
    for fm in nautilus nemo caja thunar; do
        if pgrep -x "${fm}" &>/dev/null; then
            "${fm}" -q &>/dev/null 2>&1 || true
        fi
    done
    info "Файл-менеджеры перезапущены — пункты меню появятся в новых окнах"
    info "В Nautilus/Unity скрипт живёт в ПКМ → подменю «Сценарии»/«Scripts»"
}

# ============================================
# Добавление в PATH
# ============================================
ensure_path() {
    if echo "${PATH}" | tr ':' '\n' | grep -qx "${BIN_DIR}"; then
        return 0
    fi

    local shell_name
    shell_name=$(basename "${SHELL}")
    local profile=""

    case "${shell_name}" in
        bash) profile="${HOME}/.bashrc" ;;
        zsh)  profile="${HOME}/.zshrc" ;;
        fish)
            # Fish использует другой синтаксис
            local fish_conf="${HOME}/.config/fish/conf.d/navigator.fish"
            mkdir -p "$(dirname "${fish_conf}")"
            echo "set -gx PATH ${BIN_DIR} \$PATH" > "${fish_conf}"
            ok "PATH обновлён для fish: ${fish_conf}"
            return 0
            ;;
        *)    profile="${HOME}/.profile" ;;
    esac

    if [[ -n "${profile}" ]]; then
        if ! grep -q "${BIN_DIR}" "${profile}" 2>/dev/null; then
            echo "" >> "${profile}"
            echo "# Navigator Code" >> "${profile}"
            echo "export PATH=\"${BIN_DIR}:\${PATH}\"" >> "${profile}"
            ok "PATH обновлён в ${profile}"
            warn "Выполните: source ${profile}  (или перезапустите терминал)"
        fi
    fi

    export PATH="${BIN_DIR}:${PATH}"
}

# ============================================
# Создание деинсталлятора
# ============================================
create_uninstaller() {
    cat > "${INSTALL_DIR}/uninstall.sh" <<'UNINSTALL'
#!/bin/bash
set -euo pipefail

APP_NAME="navigator"
INSTALL_DIR="${HOME}/.local/share/${APP_NAME}"
BIN_DIR="${HOME}/.local/bin"
DESKTOP_DIR="${HOME}/.local/share/applications"

echo ""
echo "Удаление Navigator Code..."
echo ""

# Удаляем лаунчеры
rm -f "${BIN_DIR}/navicode"
rm -f "${BIN_DIR}/navigator"
rm -f "${BIN_DIR}/nav"
rm -f "${BIN_DIR}/navigator-web"
echo "  ✓  Команды удалены: navicode, navigator, nav, navigator-web"

# Удаляем ярлыки из меню приложений
rm -f "${DESKTOP_DIR}/navigator-cli.desktop"
rm -f "${DESKTOP_DIR}/navigator-web.desktop"
if command -v update-desktop-database &>/dev/null; then
    update-desktop-database "${DESKTOP_DIR}" 2>/dev/null || true
fi
echo "  ✓  Ярлыки удалены из меню приложений"

# Удаляем приложение
rm -rf "${INSTALL_DIR}"
echo "  ✓  Каталог удалён: ${INSTALL_DIR}"

# Удаляем интеграцию с проводниками
rm -f "${HOME}/.local/share/nautilus/scripts/Navigator Code — Открыть здесь" 2>/dev/null || true
rm -f "${HOME}/.local/share/kio/servicemenus/navigator-code.desktop" 2>/dev/null || true
echo "  ✓  Контекстные меню проводников удалены"

# Удаляем остатки MediaHit.Pro (если был установлен)
MH_FOUND=0
[[ -d "${HOME}/.local/share/mediahit" ]] && MH_FOUND=1
[[ -e "${HOME}/.local/bin/mediahit" || -e "${HOME}/.local/bin/mediahit-web" ]] && MH_FOUND=1
[[ -e "${DESKTOP_DIR}/mediahit-cli.desktop" || -e "${DESKTOP_DIR}/mediahit-web.desktop" ]] && MH_FOUND=1
[[ -d "${HOME}/.mediahit" ]] && MH_FOUND=1
if [[ ${MH_FOUND} -eq 1 ]]; then
    rm -rf "${HOME}/.local/share/mediahit" 2>/dev/null || true
    rm -f "${HOME}/.local/bin/mediahit" "${HOME}/.local/bin/mediahit-web" 2>/dev/null || true
    rm -f "${DESKTOP_DIR}/mediahit-cli.desktop" "${DESKTOP_DIR}/mediahit-web.desktop" 2>/dev/null || true
    rm -rf "${HOME}/.mediahit" 2>/dev/null || true
    rm -f "${HOME}/.config/fish/conf.d/mediahit.fish" 2>/dev/null || true
    for profile in "${HOME}/.bashrc" "${HOME}/.zshrc" "${HOME}/.profile"; do
        if [[ -f "${profile}" ]] && grep -q "MediaHit.Pro" "${profile}" 2>/dev/null; then
            sed -i.navbak '/# MediaHit\.Pro/,+1d' "${profile}" 2>/dev/null || true
        fi
    done
    if command -v update-desktop-database &>/dev/null; then
        update-desktop-database "${DESKTOP_DIR}" 2>/dev/null || true
    fi
    echo "  ✓  Старый MediaHit.Pro также удалён"
fi

echo ""
echo "  ✓  Navigator Code удалён."
echo "  ℹ  Настройки сохранены в ~/.navigator/ (удалите вручную при необходимости)"
echo ""
UNINSTALL

    chmod +x "${INSTALL_DIR}/uninstall.sh"
}

# ============================================
# Основной процесс
# ============================================
cleanup_old_mediahit() {
    local mh_install="${HOME}/.local/share/mediahit"
    local mh_bin1="${HOME}/.local/bin/mediahit"
    local mh_bin2="${HOME}/.local/bin/mediahit-web"
    local mh_desktop_dir="${HOME}/.local/share/applications"
    local mh_desktop1="${mh_desktop_dir}/mediahit-cli.desktop"
    local mh_desktop2="${mh_desktop_dir}/mediahit-web.desktop"
    local mh_settings="${HOME}/.mediahit"
    local mh_fish="${HOME}/.config/fish/conf.d/mediahit.fish"

    local found=0
    [[ -d "${mh_install}" ]] && found=1
    [[ -e "${mh_bin1}" || -e "${mh_bin2}" ]] && found=1
    [[ -e "${mh_desktop1}" || -e "${mh_desktop2}" ]] && found=1
    [[ -d "${mh_settings}" ]] && found=1
    [[ -e "${mh_fish}" ]] && found=1

    if [[ ${found} -eq 0 ]]; then
        return 0
    fi

    info "Обнаружена старая установка MediaHit.Pro — удаляю..."
    rm -rf "${mh_install}" 2>/dev/null || true
    rm -f "${mh_bin1}" "${mh_bin2}" 2>/dev/null || true
    rm -f "${mh_desktop1}" "${mh_desktop2}" 2>/dev/null || true
    rm -rf "${mh_settings}" 2>/dev/null || true
    rm -f "${mh_fish}" 2>/dev/null || true

    # Чистим строки PATH с пометкой # MediaHit.Pro в shell-профилях
    for profile in "${HOME}/.bashrc" "${HOME}/.zshrc" "${HOME}/.profile"; do
        if [[ -f "${profile}" ]] && grep -q "MediaHit.Pro" "${profile}" 2>/dev/null; then
            sed -i.navbak '/# MediaHit\.Pro/,+1d' "${profile}" 2>/dev/null || true
        fi
    done

    if command -v update-desktop-database &>/dev/null; then
        update-desktop-database "${mh_desktop_dir}" 2>/dev/null || true
    fi
    ok "Старый MediaHit.Pro удалён"
}

# ============================================
# Установка Python и pip-пакетов (для анализа данных, документов, PDF)
# ============================================
setup_python() {
    local py_bin=""
    # Ищем подходящий python3 >= 3.9
    for cand in python3.12 python3.11 python3.10 python3.9 python3; do
        if command -v "${cand}" &>/dev/null; then
            local v
            v=$("${cand}" -c 'import sys;print("%d%02d"%sys.version_info[:2])' 2>/dev/null || echo 0)
            if [[ "${v}" -ge 309 ]]; then py_bin="${cand}"; break; fi
        fi
    done

    if [[ -z "${py_bin}" ]]; then
        warn "Python 3.9+ не найден."
        # Пробуем установить через пакетный менеджер (без sudo-запроса — только подсказка)
        if command -v apt-get &>/dev/null; then
            info "Установите: sudo apt install -y python3 python3-venv python3-pip"
        elif command -v dnf &>/dev/null; then
            info "Установите: sudo dnf install -y python3 python3-pip"
        elif command -v pacman &>/dev/null; then
            info "Установите: sudo pacman -S --noconfirm python python-pip"
        fi
        warn "Python-пакеты не установлены — анализ данных/документов будет недоступен"
        return 0
    fi
    info "Python: ${py_bin} ($(${py_bin} --version 2>&1))"

    # Проверка наличия venv-модуля
    if ! "${py_bin}" -c 'import venv' &>/dev/null; then
        warn "Модуль venv отсутствует. Установите: sudo apt install -y python3-venv"
        return 0
    fi

    local venv_dir="${INSTALL_DIR}/python/.venv"
    mkdir -p "${INSTALL_DIR}/python"
    if [[ ! -d "${venv_dir}" ]]; then
        info "Создание venv в ${venv_dir}..."
        "${py_bin}" -m venv "${venv_dir}" || { warn "venv создать не удалось"; return 0; }
    fi

    local pip="${venv_dir}/bin/pip"
    "${pip}" install --quiet --upgrade pip 2>/dev/null || true

    # Определяем архитектуру для выбора папки с wheels
    local arch
    arch=$(uname -m)
    local wheels_dir=""
    case "${arch}" in
        x86_64|amd64) wheels_dir="${SCRIPT_DIR}/python-wheels-linux-x86_64" ;;
        aarch64|arm64) wheels_dir="${SCRIPT_DIR}/python-wheels-linux-aarch64" ;;
    esac

    local req="${SCRIPT_DIR}/requirements.txt"
    if [[ ! -f "${req}" ]]; then
        warn "requirements.txt не найден рядом с installer — пропускаю установку пакетов"
        return 0
    fi

    if [[ -n "${wheels_dir}" && -d "${wheels_dir}" ]]; then
        info "Установка пакетов из bundled wheels (${wheels_dir})..."
        "${pip}" install --no-index --find-links="${wheels_dir}" -r "${req}" \
            && ok "Python-пакеты установлены из оффлайн-wheels" \
            || warn "Часть пакетов не установилась из wheels (возможно, не та ABI) — пробую онлайн"
    fi

    # Если bundled wheels нет или часть пакетов не поставилась — ставим онлайн
    info "Проверка/добор пакетов через PyPI..."
    "${pip}" install -r "${req}" \
        && ok "Python-пакеты готовы" \
        || warn "Не удалось установить часть Python-пакетов (нет интернета?)"

    # Симлинки для удобства вызова из агента
    ln -sf "${venv_dir}/bin/python" "${BIN_DIR}/navigator-python" 2>/dev/null || true
    ln -sf "${venv_dir}/bin/pip" "${BIN_DIR}/navigator-pip" 2>/dev/null || true
    ok "Доступно: navigator-python, navigator-pip"
}

cleanup_previous_navigator() {
    # Автоматическое удаление предыдущей установки Navigator Code.
    # Запускается ПЕРЕД установкой — гарантирует чистое состояние.
    local found=0
    [[ -d "${INSTALL_DIR}" ]] && found=1
    [[ -e "${BIN_DIR}/navicode" || -e "${BIN_DIR}/navigator" || -e "${BIN_DIR}/nav" ]] && found=1
    [[ -e "${BIN_DIR}/navigator-web" ]] && found=1

    if [[ ${found} -eq 0 ]]; then return 0; fi

    info "Обнаружена предыдущая установка Navigator Code — удаляю..."

    # Команды
    rm -f "${BIN_DIR}/navicode" "${BIN_DIR}/navigator" "${BIN_DIR}/nav" "${BIN_DIR}/navigator-web" 2>/dev/null || true

    # Ярлыки
    local desktop_dir="${HOME}/.local/share/applications"
    rm -f "${desktop_dir}/navigator-cli.desktop" "${desktop_dir}/navigator-web.desktop" 2>/dev/null || true

    # Контекстные меню файл-менеджеров
    rm -f "${HOME}/.local/share/file-manager/actions/navigator-code.desktop" 2>/dev/null || true
    rm -f "${HOME}/.local/share/nautilus/scripts/Navigator Code — Открыть здесь" 2>/dev/null || true
    rm -f "${HOME}/.local/share/nemo/scripts/Navigator Code — Открыть здесь" 2>/dev/null || true
    rm -f "${HOME}/.local/share/nemo/actions/navigator-code.nemo_action" 2>/dev/null || true
    rm -f "${HOME}/.config/caja/scripts/Navigator Code — Открыть здесь" 2>/dev/null || true
    rm -f "${HOME}/.local/share/kio/servicemenus/navigator-code.desktop" 2>/dev/null || true

    # Приложение (но НЕ ~/.navigator — там настройки пользователя)
    rm -rf "${INSTALL_DIR}" 2>/dev/null || true

    if command -v update-desktop-database &>/dev/null; then
        update-desktop-database "${desktop_dir}" 2>/dev/null || true
    fi

    ok "Предыдущая установка удалена"
}

main() {
    # 0. Удаляем предыдущую установку Navigator + старый MediaHit
    cleanup_previous_navigator
    cleanup_old_mediahit
    echo ""

    # Гарантируем наличие ~/.local/bin
    mkdir -p "${BIN_DIR}"

    # 1. Node.js
    echo -e "${BOLD}[1/6] Node.js${NC}"
    if ! check_node; then
        install_node_portable
    fi
    echo ""

    # 2. Приложение
    echo -e "${BOLD}[2/6] Приложение${NC}"
    install_app
    echo ""

    # 3. Команды (CLI + Web GUI)
    echo -e "${BOLD}[3/6] Команды${NC}"
    create_launcher
    echo ""

    # 4. PATH
    echo -e "${BOLD}[4/6] PATH${NC}"
    ensure_path
    create_uninstaller
    echo ""

    # 5. Ярлыки в меню приложений + контекстные меню проводников
    echo -e "${BOLD}[5/6] Меню приложений и контекстные меню${NC}"
    create_desktop_entries
    create_filemanager_integration
    echo ""

    # 6. Python + пакеты для работы с данными и документами
    echo -e "${BOLD}[6/6] Python и пакеты (данные, документы, PDF)${NC}"
    setup_python
    echo ""

    # Готово
    echo -e "${BOLD}============================================${NC}"
    echo -e "${GREEN}${BOLD}  Установка завершена!${NC}"
    echo -e "${BOLD}============================================${NC}"
    echo ""
    echo "  Запуск CLI (терминал):"
    echo "    navicode          (также: navigator, nav)"
    echo ""
    echo "  Запуск Web GUI (браузер):"
    echo "    navigator-web"
    echo ""
    echo "  Также доступно в меню приложений (Activities)."
    echo ""
    echo "  Удаление:"
    echo "    ${INSTALL_DIR}/uninstall.sh"
    echo ""

    # Проверяем доступность
    if command -v navicode &>/dev/null; then
        ok "Navigator Code готов к работе!"
    else
        warn "Перезапустите терминал или выполните:"
        echo "    export PATH=\"${BIN_DIR}:\${PATH}\""
    fi
    echo ""
}

main "$@"
