#!/bin/bash

# ============================================
# КОНСТАНТЫ ДЛЯ НАСТРОЙКИ ОБНОВЛЕНИЯ
# ============================================

# Требуемое место для обновления (в ГБ)
MIN_ROOT_SPACE_FOR_INSTALL=4      # Минимальное место в корне для установки пакетов
MIN_SPACE_FOR_CACHE=3             # Минимальное место для кэша пакетов

# Вычисляем общее необходимое место
TOTAL_SPACE_NEEDED=$((MIN_ROOT_SPACE_FOR_INSTALL + MIN_SPACE_FOR_CACHE))

# Версия ROSA для обновления
TARGET_RELEASE="13"
CURRENT_RELEASE="2021.1"

# Пакеты, которые обновим отдельно (большие по размеру) - через запятую
BIG_PACKAGES="linux-firmware,chromium-browser-stable,firefox,firefox-ru,yandex-browser,newmoon,newmoon-ru"
OLD_PACKAGES="ffmpeg6 lesstif dm-script"

# Путь к файлу журнала
LOG_FILE="/var/log/update_platform.log"

# Флаг прерывания
INTERRUPTED=false

# ============================================
# КОНЕЦ КОНСТАНТ
# ============================================

# Функция для инициализации лог-файла
init_log() {
    {
        echo "========================================================================"
        echo "Update log - $(date '+%Y-%m-%d %H:%M:%S')"
        echo "========================================================================"
        echo "Script: update-r12-to-r13.sh"
        echo "Target release: ROSA $TARGET_RELEASE"
        echo "Current release: $CURRENT_RELEASE"
        echo "System: $(uname -a)"
        echo ""
    } > "$LOG_FILE"
}

# Определяем язык на основе локали
if [[ $LANG == ru* ]]; then
    LANGUAGE="ru"
else
    LANGUAGE="en"
fi

# Функции для локализованного вывода
msg() {
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local log_message="[$timestamp] $2"

    # Запись в лог
    echo "$log_message" >> "$LOG_FILE"

    # Вывод на экран
    if [[ $LANGUAGE == "en" ]]; then
        echo "$1"
    else
        echo "$2"
    fi
}

msg_error() {
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    local log_message="[$timestamp] ERROR: $2"

    # Запись в лог
    echo "$log_message" >> "$LOG_FILE"

    # Вывод на экран
    if [[ $LANGUAGE == "en" ]]; then
        echo "ERROR: $1" >&2
    else
        echo "ОШИБКА: $2" >&2
    fi
}

# Функция для проверки наличия пакетов ROSA 13 в кэше

check_rosa13_packages_in_cache() {
    local cache_dir

    # Определяем реальное расположение кэша
    if [[ -L "/var/cache/dnf" ]]; then
        # Если это симлинк, получаем целевую директорию
        cache_dir=$(readlink -f "/var/cache/dnf")
    else
        # Иначе используем стандартный путь
        cache_dir="/var/cache/dnf"
    fi

    # Проверяем, существует ли директория кэша
    if [[ ! -d "$cache_dir" ]]; then
        return 1
    fi

    # Проверяем наличие файлов пакетов ROSA 13
    if find "$cache_dir" -name "*rosa13*" -type f 2>/dev/null | head -1 | grep -q .; then
        return 0  # Найдены пакеты ROSA 13
    else
        return 1  # Пакеты ROSA 13 не найдены
    fi
}

# Функция для очистки кэша DNF
clean_dnf_cache() {
    msg "Cleaning DNF cache..." "Очищаем кэш DNF..."

    # Выполняем очистку кэша DNF
    if dnf clean all; then
        msg "DNF cache cleaned successfully." "Кэш DNF успешно очищен."
        return 0
    else
        msg_error "Failed to clean DNF cache." "Не удалось очистить кэш DNF."
        return 1
    fi
}

# Проверяем, не перенесен ли уже кэш DNF
check_dnf_cache_location() {
    if [[ -L "/var/cache/dnf" && "$(readlink /var/cache/dnf)" == "/home/dnf_cache" && -d "/home/dnf_cache" ]]; then
        return 0  # Кэш уже перенесен
    else
        return 1  # Кэш не перенесен или перенесен некорректно
    fi
}

# Функция для перемещения кэша DNF в /home
move_dnf_cache() {
    msg "Moving DNF cache to /home to free up space..." "Перемещаем кэш DNF в /home для освобождения места..."

    # Создаем новую директорию для кэша
    new_cache_dir="/home/dnf_cache"
    mkdir -p "$new_cache_dir"

    # Создаем структуру директорий
    mkdir -p "$new_cache_dir"/{packages,metadata}

    # Удаляем старый кэш (он пустой после очистки)
    if [[ -d "/var/cache/dnf" ]]; then
        rm -rf /var/cache/dnf
    fi

    # Создаем симлинк
    ln -sf "$new_cache_dir" /var/cache/dnf

    # Проверяем, что новый кэш работает
    if [[ -L "/var/cache/dnf" && "$(readlink /var/cache/dnf)" == "$new_cache_dir" && -d "$new_cache_dir" ]]; then
        msg "New DNF cache configured successfully in $new_cache_dir" "Новый кэш DNF успешно настроен в $new_cache_dir"
        return 0
    else
        msg_error "Failed to configure new DNF cache." "Не удалось настроить новый кэш DNF."
        return 1
    fi
}

# Функция для возврата кэша DNF на корневой раздел
restore_dnf_cache() {
    msg "Returning DNF cache to root partition..." "Возвращаем кэш DNF на корневой раздел..."

    # Удаляем симлинк
    rm -f /var/cache/dnf

    # Восстанавливаем оригинальную директорию
    mkdir -p /var/cache/dnf

    # Если в /home есть данные кэша, копируем их
    if [[ -d "/home/dnf_cache" && "$(ls -A /home/dnf_cache)" ]]; then
        msg "Moving cache back to root partition..." "Перемещаем кэш обратно на корневой раздел..."
        mv "/home/dnf_cache"/* /var/cache/dnf/ 2>/dev/null || true
    fi

    # Удаляем временную директорию в /home
    rm -rf "/home/dnf_cache"

    msg "DNF cache successfully returned to root partition." "Кэш DNF успешно возвращен на корневой раздел."
}

# Функция для обработки Ctrl+C
handle_interrupt() {
    INTERRUPTED=true
    echo
    msg "Update interrupted by user (Ctrl+C)." "Обновление прервано пользователем (Ctrl+C)."
    # Завершаем с кодом 130 (стандартный для SIGINT)
    exit 130
}

# Функция для выполнения обновления системы в три этапа
perform_system_update() {
    # Этап 1: Скачивание ВСЕХ пакетов, включая большие (сохраняем в кэше)
    if [[ $INTERRUPTED == true ]]; then return 1; fi
    msg "Stage 1: Downloading packages..." "Этап 1: Скачивание пакетов..."
    if dnf distrosync --releasever=$TARGET_RELEASE --downloadonly --allowerasing -y --setopt=keepcache=True; then
        msg "All packages downloaded successfully and kept in cache." "Все пакеты успешно скачаны и сохранены в кэше."
    else
        msg_error "Failed to download packages." "Не удалось скачать пакеты."
        return 1
    fi

    echo

    # Этап 2: Обновление без больших пакетов
    if [[ $INTERRUPTED == true ]]; then return 1; fi
    msg "Stage 2: Updating without large packages..." "Этап 2: Обновление без больших пакетов..."
    if dnf distrosync --releasever=$TARGET_RELEASE --exclude="$BIG_PACKAGES" --allowerasing -y --setopt=keepcache=True; then
        msg "System updated (without large packages) successfully." "Система обновлена (без больших пакетов) успешно."
    else
        msg_error "Failed to update system (without large packages)." "Не удалось обновить систему (без больших пакетов)."
        return 1
    fi

    echo

    # Этап 3: Обновление оставшихся больших пакетов
    if [[ $INTERRUPTED == true ]]; then return 1; fi
    msg "Stage 3: Updating remaining large packages..." "Этап 3: Обновление оставшихся больших пакетов..."
    if dnf distrosync --releasever=$TARGET_RELEASE --allowerasing -y; then
        msg "All packages updated succes--setopt=keepcache=Truesfully." "Все пакеты успешно обновлены."
    else
        msg_error "Failed to update remaining packages." "Не удалось обновить оставшиеся пакеты."
        return 1
    fi

    echo
    if [[ $INTERRUPTED == true ]]; then return 1; fi
    # Выполняем переустановку загрузчика
    msg "Reinstalling bootloader..." "Выполняем переустановку загрузчика..."
    if grub2-install-hooks; then
        msg "Bootloader updated successfully." "Загрузчик успешно обновлен."
    else
        msg_error "Failed to update bootloader." "Не удалось обновить загрузчика."
        return 1
    fi

    echo
    if [[ $INTERRUPTED == true ]]; then return 1; fi
    # Удаляем осиротевшие пакеты и известные пакеты от старой платформы
    msg "Removing orphaned packages with autoremove..." "Удаляем осиротевшие пакеты с помощью autoremove..."
    if dnf autoremove -y; then
        msg "Autoremove completed successfully." "Autoremove успешно завершен."
        if dnf erase $OLD_PACKAGES -y; then
          msg "Remove old packages successfully." "Удаление устаревших пакетов успешно завершено."
        else
          msg "Remove old packages failed." "Удаление устаревших пакетов завершилось с ошибкой."
        fi
    else
        msg_error "Autoremove failed, but continuing." "Autoremove завершился с ошибкой, но продолжаем."
    fi

    echo

        # Проверяем наличие пакетов от старой версии
    msg "Checking for packages from previous platorm..." "Проверяем наличие пакетов от предыдущей платформы..."
    local old_packages
    old_packages=$(rpm -qa --qf '%{name} %{sourcerpm} %{disttag}\n' | grep $CURRENT_RELEASE)

    if [[ -n "$old_packages" ]]; then
    msg "Found packages from previous platform:" "Найдены пакеты от предыдущей платформы:"
    {
        echo ""
        echo "Packages from previous platform:"
        echo "--------------------------------------------"
        echo "$old_packages"
        echo "--------------------------------------------"
    } >> "$LOG_FILE"
    # Краткое сообщение на экран
    echo "$old_packages" | head -5
    if [[ $(echo "$old_packages" | wc -l) -gt 5 ]]; then
        msg "... and more $(($(echo "$old_packages" | wc -l) - 5)) packages. See $LOG_FILE for details." "... и еще $(($(echo "$old_packages" | wc -l) - 5)) пакетов. Подробности см. в $LOG_FILE."
    fi
    else
        msg "No packages from previous platform found." "Пакетов от предыдущей платформы не найдено."
    fi
}


cleanup_system_before_update() {
    msg "Starting system cleanup to free up space..." "Начинаем очистку системы для освобождения места..."

    # 1. Сжатие журналов (оставляем записи за последние 3 дня)
    msg "Compressing system journals (keeping last 2 days)..." "Сжимаем системные журналы (оставляем последние 2 дня)..."
    if journalctl --vacuum-time=2d 2>/dev/null; then
        msg "System journals compressed successfully." "Системные журналы успешно сжаты."
    else
        msg_error "Failed to compress journals (journalctl not available?)." "Не удалось сжать журналы (journalctl недоступен?)."
    fi

    # 2. Удаление старых ядер (оставляем 2 последние версии)
    msg "Removing old kernels..." "Удаляем старые ядра..."
    if dnf remove --oldinstallonly --setopt installonly_limit=0 -y 2>/dev/null; then
        msg "Old kernels removed successfully." "Старые ядра успешно удалены."
    else
        msg "No old kernels found or error occurred." "Старые ядра не найдены или произошла ошибка."
    fi

    # 3. Удаление неиспользуемых зависимостей
    msg "Removing unused dependencies..." "Удаляем неиспользуемые зависимости..."
    if dnf autoremove -y 2>/dev/null; then
        msg "Unused dependencies removed." "Неиспользуемые зависимости удалены."
    fi

    # 4. Очистка кэша пакетов
    if ! check_rosa13_packages_in_cache; then
        clean_dnf_cache
    fi

    msg "System cleanup completed." "Очистка системы завершена."
    echo
}

#**************************************************************Начало основного кода скрипта **************************************************************************************************************
# Вывод предупреждения о обновлении
echo "========================================================================"
if [[ $LANGUAGE == "ru" ]]; then
    echo "Этот скрипт выполнит обновление системы РОСА Линукс с платформы $CURRENT_RELEASE на платформу РОСА $TARGET_RELEASE."
    echo "Перед обновлением рекомендуется:"
    echo "1. Сделать резервное копирование пользовательских данных"
    echo "2. Создать загрузочный носитель с релизом РОСА $TARGET_RELEASE для ручного обновления или релизом РОСА 12 для отката при невозможности обновления"
    echo ""
    echo "Требования к месту:"
    echo "- Корневой раздел: $MIN_ROOT_SPACE_FOR_INSTALL ГБ для установки"
    echo "- Кэш пакетов: $MIN_SPACE_FOR_CACHE ГБ для кэша пакетов"
    echo "- Всего при кэше в корне: $TOTAL_SPACE_NEEDED ГБ в корневом разделе"
else
    echo "This script will update ROSA Linux from platform $CURRENT_RELEASE to ROSA $TARGET_RELEASE."
    echo "Before updating, it is recommended to:"
    echo "1. Backup your user data"
    echo "2. Create bootable media with ROSA $TARGET_RELEASE release for manual update or ROSA 12 release for rollback if update fails"
    echo ""
    echo "Space requirements:"
    echo "- Root partition: $MIN_ROOT_SPACE_FOR_INSTALL GB for installation"
    echo "- Cache space: $MIN_SPACE_FOR_CACHE GB for package cache"
    echo "- Total needed if cache stays in root: $TOTAL_SPACE_NEEDED GB in root"
fi
echo "========================================================================"
echo

# Запрос подтверждения с использованием printf
if [[ $LANGUAGE == "ru" ]]; then
    printf "Продолжить? [Да/Нет] (y/N) (по умолчанию: Нет): "
else
    printf "Continue? [Yes/No] (default: No): "
fi
read -r confirm

# Обработка ответа (регистронезависимая)
shopt -s nocasematch
if [[ ! $confirm =~ ^(yes|да|y|д)$ ]]; then
    if [[ $LANGUAGE == "ru" ]]; then
        echo "Обновление отменено пользователем."
    else
        echo "Update cancelled by user."
    fi
    exit 0
fi
shopt -u nocasematch

echo

# Проверяем, что скрипт запущен от root
if [[ $EUID -ne 0 ]]; then
    msg_error "This script must be run as root" "Этот скрипт должен быть запущен с правами root"
    exit 1
fi

init_log
trap handle_interrupt SIGINT
msg "Starting platform update script..." "Начало выполнения скрипта обновления платформы..."
msg "Press Ctrl+C to cancel at any time." "Нажмите Ctrl+C для отмены в любой момент."

echo "================================================================================"
if [[ $LANGUAGE == "ru" ]]; then
    echo "ОЧИСТКА СИСТЕМЫ ПЕРЕД ОБНОВЛЕНИЕМ"
    echo "================================================================================"
    echo "Будет освобождено место в корневом разделе за счет удаления ненужных файлов:"
    echo ""
    echo "1. СЖАТИЕ СИСТЕМНЫХ ЛОГОВ:"
    echo "   - Сохраняются только журналы (journald) за последние 2 дня"
    echo "   - Старые файлы логов будут удалены, освободит ~100-500 МБ"
    echo ""
    echo "2. УДАЛЕНИЕ СТАРЫХ ЯДЕР:"
    echo "   - Остается только последняя версия ядра"
    echo "   - Будут удалены старые пакеты ядер и модули, освободит ~500-1500 МБ"
    echo "   - Текущее ядро всегда остается"
    echo ""
    echo "3. ОЧИСТКА КЭША ПАКЕТОВ:"
    echo "   - Удаляет скачанные .rpm файлы из кэша DNF"
    echo "   - Освободит ~200-1000 МБ (если пакеты ROSA 13 еще не скачаны)"
    echo ""
    echo "4. УДАЛЕНИЕ НЕИСПОЛЬЗУЕМЫХ ЗАВИСИМОСТЕЙ:"
    echo "   - Удаляет осиротевшие пакеты, больше не нужные установленному ПО"
    echo ""
    echo "Ожидаемый итоговый объем: 800 МБ - 3 ГБ"
    echo "================================================================================"
    printf "Выполнить очистку системы? [Да/Нет] (Y/n) (по умолчанию: Да): "
else
    echo "SYSTEM CLEANUP BEFORE UPDATE"
    echo "================================================================================"
    echo "This will free up space in the root partition by removing unnecessary files:"
    echo ""
    echo "1. COMPRESS SYSTEM LOGS:"
    echo "   - Keeps only the last 2 days of system journal (journald) logs"
    echo "   - Old log files will be deleted, freeing ~100-500 MB"
    echo ""
    echo "2. REMOVE OLD KERNELS:"
    echo "   - Keeps only latest kernel"
    echo "   - Old kernel packages and modules will be removed, freeing ~500-1500 MB"
    echo "   - At least one working kernel will always remain"
    echo ""
    echo "3. CLEAN PACKAGE CACHE:"
    echo "   - Removes downloaded .rpm files from DNF cache"
    echo "   - Frees ~200-1000 MB (unless ROSA 13 packages are already downloaded)"
    echo ""
    echo "4. REMOVE UNUSED DEPENDENCIES:"
    echo "   - Removes orphaned packages no longer needed by any installed software"
    echo ""
    echo "Total expected space freed: 800 MB - 3 GB"
    echo "================================================================================"
    printf "Continue? [Yes/No] (default: Yes): "
fi

read -r cleanup_confirm
# Обработка ответа
shopt -s nocasematch
if [[ ! $cleanup_confirm =~ ^(no|нет|n|н)$ ]]; then
    cleanup_system_before_update
fi
shopt -u nocasematch


if check_rosa13_packages_in_cache; then
    # Если в кэше уже есть пакеты ROSA 13, значит обновление уже начиналось
    msg "Found ROSA $TARGET_RELEASE packages in cache, skipping space check and cache cleanup" "Найдены пакеты ROSA $TARGET_RELEASE в кэше, пропускаем проверку места и очистку кэша"
    # Выполняем обновление системы
    if perform_system_update; then
        # Если кэш был перемещен, возвращаем его
        if check_dnf_cache_location; then
            restore_dnf_cache
        fi

        # Перезагружаем систему
        msg "System will reboot in 10 seconds..." "Система будет перезагружена через 10 секунд..."
        sleep 10
        reboot
    else
        exit 1
    fi

else

    # Проверяем доступное место в корневом разделе и /home
    root_space=$(df / --output=avail | tail -1)
    home_space=$(df /home --output=avail 2>/dev/null | tail -1)

    # Конвертируем в ГБ (1 ГБ = 1048576 КБ)
    root_gb=$((root_space / 1048576))

    # Если /home существует, получаем свободное место, иначе считаем 0
    if [[ -n "$home_space" ]]; then
        home_gb=$((home_space / 1048576))
    else
        home_gb=0
    fi

    msg "Free in root: $root_gb GB" "Свободно в корне: $root_gb ГБ"
    if [[ $home_gb -gt 0 ]]; then
        msg "Free in /home: $home_gb GB" "Свободно в /home: $home_gb ГБ"
    fi

    # Проверяем условия для выполнения обновления

    # Проверяем, находятся ли корень и /home на одном разделе
    root_device=$(df / --output=source | tail -1)
    if [[ -d "/home" ]]; then
        home_device=$(df /home --output=source 2>/dev/null | tail -1)
    else
        home_device=""
    fi

    # Если /home не существует или корень и /home на одном разделе
    if [[ -z "$home_device" ]] || [[ "$root_device" == "$home_device" ]]; then
        # Если /home нет или они на одном разделе, нужно TOTAL_SPACE_NEEDED ГБ в корне
        if [[ $root_gb -ge $TOTAL_SPACE_NEEDED ]]; then
            msg "Enough space in root partition. Starting system update..." "Достаточно места в корневом разделе. Запускаем обновление системы..."

            # Выполняем обновление системы
            if perform_system_update; then
                # Перезагружаем систему
                msg "System will reboot in 10 seconds..." "Система будет перезагружена через 10 секунд..."
                sleep 10
                reboot
            else
                exit 1
            fi
        else
            msg_error "Not enough space for system update." "Недостаточно места для обновления системы."

            if [[ $LANGUAGE == "en" ]]; then
                echo "Need $TOTAL_SPACE_NEEDED GB free in root partition."
                echo "Current: root has $root_gb GB"
                echo ""
                echo "/home is on the same partition or doesn't exist, cannot move cache to save space."
            else
                echo "Нужно $TOTAL_SPACE_NEEDED ГБ свободно в корневом разделе."
                echo "Сейчас: в корне $root_gb ГБ"
                echo ""
                echo "/home находится на том же разделе или отсутствует, невозможно переместить кэш для экономии места."
            fi
            exit 1
        fi
    else
        # Если корень и /home на разных разделах
        if [[ $root_gb -ge $TOTAL_SPACE_NEEDED ]]; then
            msg "Enough space in root partition. Starting system update..." "Достаточно места в корневом разделе. Запускаем обновление системы..."

            # Выполняем обновление системы
            if perform_system_update; then
                # Перезагружаем систему
                msg "System will reboot in 10 seconds..." "Система будет перезагружена через 10 секунд..."
                sleep 10
                reboot
            else
                exit 1
            fi
        elif [[ $root_gb -ge $MIN_ROOT_SPACE_FOR_INSTALL && $home_gb -ge $MIN_SPACE_FOR_CACHE ]]; then
            msg "Not enough space in root, moving cache to /home..." "Недостаточно места в корне, перемещаем кэш в /home..."

            # Перемещаем кэш DNF
            if move_dnf_cache; then
                # Выполняем обновление системы
                if perform_system_update; then
                    # Возвращаем кэш на корневой раздел
                    restore_dnf_cache

                    # Перезагружаем систему
                    msg "System will reboot in 10 seconds..." "Система будет перезагружена через 10 секунд..."
                    sleep 10
                    reboot
                else
                    # В случае ошибки обновления, возвращаем кэш
                    restore_dnf_cache
                    exit 1
                fi
            else
                exit 1
            fi
        else
            msg_error "Not enough space for system update." "Недостаточно места для обновления системы."

            if [[ $LANGUAGE == "en" ]]; then
                echo "Need either:"
                echo "  - $TOTAL_SPACE_NEEDED GB free in root partition (if cache stays in root), OR"
                echo "  - $MIN_ROOT_SPACE_FOR_INSTALL GB free in root and $MIN_SPACE_FOR_CACHE GB free in /home (to move cache to /home)"
                echo "Current: root has $root_gb GB, /home has $home_gb GB"
            else
                echo "Нужно либо:"
                echo "  - $TOTAL_SPACE_NEEDED ГБ свободно в корневом разделе (если кэш остается в корне), ИЛИ"
                echo "  - $MIN_ROOT_SPACE_FOR_INSTALL ГБ свободно в корне и $MIN_SPACE_FOR_CACHE ГБ свободно в /home (чтобы переместить кэш в /home)"
                echo "Сейчас: в корне $root_gb ГБ, в /home $home_gb ГБ"
            fi
            exit 1
        fi
    fi
fi
