#!/bin/bash

#Этот скрипт -- неофициальное решение от АСКОН для установки КОМПАС-3D и всех компонентов, включая Библиотеку Стандартных Изделий, на Debian 13.
#Обратите внимание, что КОМПАС-3D для Linux официально поддерживается только на трёх операционных системах: Astra Linux Special Edition 1.8, Альт Рабочая Станция 11 / К11 и РЕД ОС 8. 
#Используйте, редактируйте и распространяйте этот скрипт на свой страх и риск.

set -euo pipefail

# Цвета
RED=$'\033[0;31m'
YELLOW=$'\033[1;33m'
NC=$'\033[0m'

#Проверка на root
if [[ $EUID != 0 ]]; then
    echo "${RED}ВНИМАНИЕ: Скрипт предназначен для запуска от суперпользователя. Пожалуйста, перезапустите скрипт от имени root или с sudo."
    exit 1
fi

# Создание рабочих директорий и файла логирования
WORKDIR="$HOME/kompas-install"
DOWNLOAD_DIR="$WORKDIR/downloads"
EXTRACT_DIR="$WORKDIR/extracted"
START_TIME=$(date '+%Y-%m-%d_%H-%M-%S')
LOGS="$WORKDIR/$START_TIME.log"

for dir in "$WORKDIR" "$DOWNLOAD_DIR" "$EXTRACT_DIR"; do
    mkdir -p "$dir" || { echo "Не удаётся создать рабочий каталог: $dir" >&2; exit 1; }
done

touch "$LOGS"
: > "$LOGS" 2>/dev/null || { echo "Ошибка создания или записи файла логирования $LOGS" >&2; exit 1; }

# Задаём функции логирования
log() {
    local TIMESTAMP
    TIMESTAMP=$(date '+%T');
    echo -e "[$TIMESTAMP] $*" | tee -a "$LOGS";
}

warn() {
    local TIMESTAMP
    TIMESTAMP=$(date '+%T');
    echo -e "${YELLOW}[$TIMESTAMP] ВНИМАНИЕ: $*${NC}";
    echo -e "[$TIMESTAMP] ВНИМАНИЕ:\n$*\n---------------------" &>> "$LOGS";
}

error() {
    local TIMESTAMP
    TIMESTAMP=$(date '+%T');
    echo "${RED}[$TIMESTAMP] ОШИБКА: $*${NC}";
    echo -e "${RED}Файл логирования доступен для изучения по пути: $LOGS${NC}";
    echo -e "[$TIMESTAMP] ОШИБКА:\n$*\n-------------------" &>> "$LOGS";
    exit 1
}

#Функция вопроса
ask() {
    echo -n "$* (y/n): " | tee -a "$LOGS" || warn "Ошибка записи в лог";
    local answer
    while true
    do
        read -r answer || return 1
        case "$answer" in
            [Yy]|[Yy][Ee][Ss]|[Дд]|[Дд][Аа])
                echo "Ответ: да" >> "$LOGS" || warn "Ошибка записи в лог"
                return 0 ;;
            [Nn]|[Nn][Oo]|[Нн]|[Нн][Ее][Тт])
                echo "Ответ: нет" >> "$LOGS" || warn "Ошибка записи в лог"
                return 1 ;;
            *) echo -n "Некорректный ввод. $* (y/n): " | tee -a "$LOGS" || warn "Ошибка записи в лог";;
        esac
    done
}

#Функция проверки дистрибутива
DIST_NAME=""
check_dist() {
    if [[ -f /etc/os-release ]]; then
        . /etc/os-release
        if [[ "$ID" != "debian" || "$VERSION_ID" != "13" ]]; then
            warn "Кажется, вы используете $PRETTY_NAME в качестве операционной системы. Данный скрипт написан и протестирован для Debian 13."
            ask "Продолжить установку на $PRETTY_NAME?" || error "Установка прервана пользователем."
        fi
        if [[ "$ID" == "debian" && "$VERSION_ID" == "13" ]]; then
            warn "Для удовлетворения зависимостей пакетов на Debian 13 будет подключён дополнительный репозиторий dotnet"
            download https://packages.microsoft.com/config/debian/13/packages-microsoft-prod.deb
            dpkg -i "$DOWNLOAD_DIR/packages-microsoft-prod.deb" || warn "Не удалось установить репоизторий dotnet для Debian 13"
            # download https://mirror.yandex.ru/ubuntu/pool/main/i/icu/libicu74_74.2-1ubuntu3.1_amd64.deb
            # apt install "$DOWNLOAD_DIR/libicu74_74.2-1ubuntu3.1_amd64.deb" || warn "Не удалось установить libicu74 для Debian 13"
        fi
        DIST_NAME="$ID $VERSION_ID"
    else
        warn "Не удаётся определить версию дистрибутива. Данный скрипт написан и протестирован для Debian 13."
        ask "Продолжить с неизвестным дистрибутивом?" || error "Установка прервана пользователем."
    fi
}

#Функция проверки свободного пространства на диске
check_space() {
    if (( $(df /opt/ --output=avail --block-size=1G | tail -1) < 75 || $(df "$WORKDIR" --output=avail --block-size=1G | tail -1) < 70 )); then
        warn "В целевой папке недостаточно свободного места. Скорее всего, установка пройдёт неудачно. Для установки рекомендуется иметь не менее 75 Гб свободного дискового пространства в директории /opt и не менее 70 Гб в директории $WORKDIR."
        ask "Продолжить установку?" || error "Установка прервана пользователем."
    fi
}

#Функция загрузки файла
download() {
    local url
    local rc=0
    local retry=1
    while (( retry != 0 )); do
        for url in "$@"; do
            log "Скачивается: $url"
            wget -t 10 --show-progress -c -nc -P "$DOWNLOAD_DIR" "$url" || { warn "Ошибка скачивания файла: $url. Будет предоставлена возможность повторить попытку скачивания после окончания загрузки остальных файлов."; rc=1; }
        done
        if (( rc != 0 )); then
            warn "Ошибка скачивания"
            if ! ask "Повторить попытку скачивания?"; then
                error "Ошибка скачивания. Скрипт остановлен пользователем."
            fi
        else
            retry=0
        fi
    done
}

#Функция подключения репозитория КОМПАС-3D
add_repo(){
    local add_main=0
    local add_personal=0
    local version=$1
    if [[ "$version" == "ascon-kompas3d-v25-full" ]]; then
        if [[ -f /etc/apt/sources.list.d/ascon.list ]]; then
            if ask "Обнаружен файл репозитория АСКОН. Обновить репозиторий?"; then
                add_main=1
            fi
        else
            add_main=1
        fi
    else
        if [[ -f /etc/apt/sources.list.d/ascon-personal.list || -f /etc/apt/sources.list.d/ascon.list ]]; then
            if ask "Обнаружены файлы репозиториев АСКОН. Обновить репозитории?"; then
                add_main=1
                add_personal=1
            fi
        else
            add_main=1
            add_personal=1
        fi
    fi
    if (( add_main )); then
        bash -c "$(wget -O - https://repo.ascon.ru/scripts/ascon-stable-deb.sh)" || true
        echo "deb [signed-by=/etc/apt/trusted.gpg.d/ascon.gpg] https://repo.ascon.ru/stable/deb 1.8_x86-64 main" | tee /etc/apt/sources.list.d/ascon.list >/dev/null || warn "Не удалось отредактировать файл основного репозитория АСКОН"
    fi
    if (( add_personal )); then
        bash -c "$(wget -O - https://repo.ascon.ru/personal/scripts/ascon-personal-deb.sh)" || true
        echo "deb [signed-by=/etc/apt/trusted.gpg.d/ascon.gpg] https://repo.ascon.ru/personal/deb 1.8_x86-64 main" | tee /etc/apt/sources.list.d/ascon-personal.list >/dev/null || warn "Не удалось отредактировать файл некоммерческого репозитория АСКОН"
    fi
    apt update || warn "Ошибка получения метаданных пакетов. Возможно, репозиторий сконфигурировался некорректно."
}

#Первичная настройка и предупреждения
log "Этот скрипт установит КОМПАС-3D и все доступные библиотеки на Debian. Обратите внимание, что КОМПАС-3D официально  поддерживается только на операционных системах Astra Linux Special Edition 1.8, Альт Рабочая Станция 11/К11 и РЕД ОС 8. Данный скрипт является неофициальным решением, использует множество костылей и поставляется "как есть". Продолжая, вы подтверждаете, что осознаёте вероятность негативного влияния этого скрипта на вашу систему и принимаете риск."
ask "Подтвердите продолжение" || error "Установка прервана пользователем."

check_dist
check_space

KOMPAS_VERSION=ascon-kompas3d-v25-full
KOMPAS_COMMAND=kompas-v25

while true; do
    echo "Выберите необходимую версию КОМПАС-3D [1]:" | tee -a "$LOGS" || warn "Ошибка записи в лог"
    echo "  1) КОМПАС-3D v25 (коммерческая) - вариант по умолчанию" | tee -a "$LOGS" || warn "Ошибка записи в лог"
    echo "  2) КОМПАС-3D v25 Home (домашняя)" | tee -a "$LOGS" || warn "Ошибка записи в лог"
    echo "  3) КОМПАС-3D v25 Study (учебная)" | tee -a "$LOGS" || warn "Ошибка записи в лог"
    read -r answer || error "Не удалось считать ответ"
    case "$answer" in
    "" | 1)
        break
        ;;
    2)
        KOMPAS_VERSION=ascon-kompas3d-home-v25-full
        KOMPAS_COMMAND=kompas-home-v25
        break
        ;;
    3)
        KOMPAS_VERSION=ascon-kompas3d-study-v25-full
        KOMPAS_COMMAND=kompas-study-v25
        break
        ;;
    *)
        echo "Некорректное значение."
        ;; 
    esac
    echo $KOMPAS_VERSION >> "$LOGS" || warn "Ошибка записи в лог"
done

#Установка дополнительных пакетов
apt update || warn "Ошибка получения метаданных пакетов."
apt install -y curl gnupg locales desktop-file-utils libxcb-res0 libxcb-xkb1 libxcb-xinput0 rpm2cpio cpio binutils || error "Не удалось установить необходимые пакеты"

#Установка необходимых локалей
sed -i 's/^# *\(ru_RU\.UTF-8 UTF-8\)/\1/' /etc/locale.gen || warn "Не удалось сгенерировать локали"
sed -i 's/^# *\(en_US\.UTF-8 UTF-8\)/\1/' /etc/locale.gen || warn "Не удалось сгенерировать локали"
locale-gen || warn "Не удалось сгенерировать локали"

#Подключение репозиториев и обновление метаданных
add_repo "$KOMPAS_VERSION"

#Установка КОМПАС-3D
log "Устанавливаем $KOMPAS_VERSION"
INSTALL_LOG="$WORKDIR/$START_TIME-main-install.log"
touch "$INSTALL_LOG"
apt install -y $KOMPAS_VERSION ascon-common-coredump-watcher 2>&1 | tee -a "$INSTALL_LOG" || true
pipe_status=("${PIPESTATUS[@]}")
[[ ${pipe_status[0]:-0} -ne 0 ]] && warn "Проблема при установке КОМПАС-3D" || true
[[ ${pipe_status[1]:-0} -ne 0 ]] && warn "Ошибка записи в лог установки основных пакетов" || true
ERRORS=$(grep -E '^(dpkg: error|E:|Errors were|Error:)' "$INSTALL_LOG" || true)

attempt=0
while [[ -n $ERRORS ]]; do
    warn "Возникла ошибка при установке КОМПАС-3D."
    if [[ $ERRORS == *--configure* ]]; then
        warn "Обнаружена ошибка конфигурирования пакетов. Будет предпринята попытка выполнить конфигурацию вручную, без нецелевого пакета библиотеки СИ и МиС"
        if [[ $DIST_NAME == "debian 13" ]]; then
            warn "Это нормальное поведение для установки на Debian 13"
        fi
        sed -i '1a exit 0' /var/lib/dpkg/info/ascon-polynom-library-24.0.postinst || error "Не удалось исправить postinst-скрипт библиотеки СИ и МиС"
        dpkg --configure -a || error "Не удалось сконфигурировать пакеты с обработкой ошибки конфигурации"
        apt install -f || error "Не удалось сконфигурировать пакеты с обработкой ошибки конфигурации"
        apt install -y $KOMPAS_VERSION ascon-common-coredump-watcher 2>&1 | tee "$INSTALL_LOG" || true
        pipe_status=("${PIPESTATUS[@]}")
        [[ ${pipe_status[0]:-0} -ne 0 ]] && warn "Проблема при установке КОМПАС-3D"
        [[ ${pipe_status[1]:-0} -ne 0 ]] && warn "Ошибка записи в лог установки основных пакетов"
    elif [[ $ERRORS == *ascon-polynom-library* ]]; then
        warn "Обнаружена ошибка установки библиотеки СИ и МиС."
        if ask "Попробовать установить КОМПАС-3D, скачивая пакет Библиотеки Стандартных изделий через wget?"; then
            wget -t 10 --show-progress -c -nc -P "$DOWNLOAD_DIR" https://repo.ascon.ru/stable/deb/pool/main/a/ascon/ascon-polynom-library-24.0-24.0.0.26061516-amd64.deb || error "Не удалось скачать пакет Библиотеки Стандартных изделий"
            apt install "$DOWNLOAD_DIR/ascon-polynom-library-24.0-24.0.0.26061516-amd64.deb" 2>&1 | tee "$INSTALL_LOG" || true
            pipe_status=("${PIPESTATUS[@]}")
            [[ ${pipe_status[0]:-0} -ne 0 ]] && warn "Проблема при установке отдельной библиотеки СИ и МиС"
            [[ ${pipe_status[1]:-0} -ne 0 ]] && warn "Ошибка записи в лог установки основных пакетов"
            apt install -y "$KOMPAS_VERSION" ascon-common-coredump-watcher 2>&1 | tee -a "$INSTALL_LOG" || true
            pipe_status=("${PIPESTATUS[@]}")
            [[ ${pipe_status[0]:-0} -ne 0 ]] && warn "Проблема при установке КОМПАС-3D"
            [[ ${pipe_status[1]:-0} -ne 0 ]] && warn "Ошибка записи в лог установки основных пакетов"
        else
            error "Не удалось установить КОМПАС-3D: пользователь отказался от ручного режима установки."
        fi
    else
        warn "Обнаружена неизвестная ошибка установки КОМПАС-3D. Скорее всего, дальнейшая установка пройдёт неудачно."
        if ask "Продолжить установку?"; then
            warn "Установка будет продолжена несмотря на ошибки в процессе установки основных пакетов КОМПАС-3D"
            break
        else
            error "Не удалось установить КОМПАС-3D: пользователь отказался от ручного режима установки."
        fi
    fi
    ERRORS=$(grep -E '^(dpkg: error|E:|Errors were|Error:)' "$INSTALL_LOG" || true)
    attempt+=1
    if (( attempt > 3 )); then
        if ask "Кажется, несколько попыток решения проблем при установке КОМПАС-3D завершились неудачей. Прервать дальнейшие попытки установки?"; then
            error "Не удалось установить КОМПАС-3D: пользователь отказался от продолжения после множества неудачных попыток установки."
        else
            attempt=0
        fi
    fi
done
rm "$INSTALL_LOG" || warn "Ошибка удаления лога установки основных пакетов"

rm -rf /opt/ascon/polynom-library || error "Не удалось очистить директорию polynom-library"

log "Установка Polynom из Альт 11..."
log "В качестве рабочей директории будет использована $WORKDIR"

ALT_BASE="https://repo.ascon.ru/stable/alt/p11/x86_64/RPMS.main"
RPM_URLS=(
    "$ALT_BASE/ascon-polynom-library-24.0-24.0.0.26061516-0.x86_64.rpm"
    "$ALT_BASE/ascon-polynom-library-database-part1-24.0-24.0.0.26051921-0.x86_64.rpm"
    "$ALT_BASE/ascon-polynom-library-database-part2-24.0-24.0.0.26051921-0.x86_64.rpm"
    "$ALT_BASE/ascon-polynom-library-database-part3-24.0-24.0.0.26051921-0.x86_64.rpm"
    "$ALT_BASE/ascon-polynom-library-database-part4-24.0-24.0.0.26051921-0.x86_64.rpm"
    "$ALT_BASE/ascon-polynom-library-database-part5-24.0-24.0.0.26051921-0.x86_64.rpm"
)

log "Скачиваем и распаковываем .rpm-пакеты из репозитория для Альт РС 11..."
download "${RPM_URLS[@]}"
for rpm in "$DOWNLOAD_DIR"/*.rpm; do
    rpm2cpio "$rpm" | cpio -D "$EXTRACT_DIR" -idmv || warn "Ошибка извлечения архивов .rpm"
done

log "Переносим распакованную базу данных в директорию polynom..."
mv "$EXTRACT_DIR/opt/ascon/polynom-library" "/opt/ascon/" || error "Не удалось перенести новую базу данных в необходимое место"

log "Правим конфигурацию сервиса для использования встроенных библиотек..."

log "Создаём симлинки к встроенным библиотекам..."
LIB64="/opt/ascon/polynom-library/database/pg/lib64"
for f in "$LIB64/"*.so.*; do
    [[ -f "$f" ]] || continue
    soname=$(readelf -d "$f" 2>/dev/null | sed -n 's/.*SONAME.*\[\(.*\)\].*/\1/p')
    ln -sf "$f" "$LIB64/$soname" || warn "Не удалось создать симлинк $soname"
done
sudo sed -i 's|Environment=LD_LIBRARY_PATH=/opt/ascon/polynom-library/database/pg/lib$|Environment=LD_LIBRARY_PATH=/opt/ascon/polynom-library/database/pg/lib:/opt/ascon/polynom-library/database/pg/lib64|' /etc/systemd/system/polynompg.service || warn "Ошибка редактирования файла конфигурации сервиса базы данных Polynom"
sudo systemctl daemon-reload || warn "Ошибка перезагрузки системных юнитов"

if [[ $DIST_NAME == "debian 13" ]]; then
    log "Дополняем ярлык запуска программы переменной инвариантного режима глобализации Dotnet..."
    desktop=/usr/share/applications/$KOMPAS_COMMAND.desktop
    if ! grep -q '^Exec=env DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 ' "$desktop"; then
        sed -i 's|^Exec=|Exec=env DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 |' "$desktop" || warn "Не удалось отредактировать ярлык КОМПАС-3D"
    fi
    warn "Для корректного запуска библиотеки Стандартных изделий при запуске КОМПАС-3D из терминала необходимо использовать переменную окружения DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1.\nПроще всего это сделать с помощью команды:\nenv DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 $KOMPAS_COMMAND"
fi

log "Устанавливаем права в Библиотеке Стандартных изделий..."
chown -R root:root /opt/ascon/polynom-library || error "Не удалось установить права"
chmod -R 775 /opt/ascon/polynom-library || error "Не удалось установить права"
chown -R polynom:root /opt/ascon/polynom-library/database || error "Не удалось установить права"
chmod -R 750 /opt/ascon/polynom-library/database || error "Не удалось установить права"

log "Запускаем службу Библиотеки Стандартных изделий..."
# systemctl restart polynompg.service
systemctl restart polynomlib.service
systemctl restart polynom.service

log "Установка завершена. Лог установки доступен для изучения по пути: $LOGS"
if ask "В процессе установки было использовано много дополнительного пространства. Очистить рабочую директорию?"; then
    rm -rf "$DOWNLOAD_DIR"
    rm -rf "$EXTRACT_DIR"
fi

if ask "Рекомендуется перезапустить систему после установки. Начать перезагрузку?"; then
    reboot
fi