#!/bin/sh

# Скрипт для отображения дерева зависимостей пакета в FreeBSD

show_usage() {
    echo "Использование: $0 [-s] <имя пакета>"
    echo "Опции:"
    echo "  -s    Показывать системные зависимости как 'системная зависимость'"
    echo "Примеры:"
    echo "  $0 nano          # Полное дерево зависимостей"
    echo "  $0 -s nano       # Скрыть системные пакеты"
    exit 1
}

# Переменные по умолчанию
SHOW_SYSTEM_DETAILS=true
PKG_NAME=""

# Разбор аргументов командной строки
while getopts "s" opt; do
    case $opt in
        s)
            SHOW_SYSTEM_DETAILS=false
            ;;
        \?)
            show_usage
            ;;
    esac
done

# Сдвигаем аргументы, чтобы получить имя пакета
shift $((OPTIND - 1))

# Проверка наличия имени пакета
if [ $# -eq 0 ]; then
    show_usage
fi

PKG_NAME="$1"

# Проверка установлен ли пакет
if ! pkg info "$PKG_NAME" > /dev/null 2>&1; then
    echo "Пакет '$PKG_NAME' не найден или не установлен"
    exit 1
fi

# Функция для проверки, является ли пакет системным
# Системные пакеты начинаются с FreeBSD- и содержат версию
is_system_package() {
    local pkg="$1"
    
    # Проверяем, начинается ли имя с FreeBSD-
    if echo "$pkg" | grep -q "^FreeBSD-"; then
        # Проверяем, содержит ли версию (цифры после последнего дефиса)
        #if echo "$pkg" | grep -q -- '-[0-9][0-9.]*$'; then
        #    return 0  # Это системный пакет
        #fi
        return 0
    fi
    return 1  # Не системный пакет
}

# Функция для очистки имени пакета (удаляем версию и скобки с библиотеками)
clean_pkg_name() {
    local pkg="$1"
    # Удаляем все после первого пробела (включая скобки с библиотеками)
    echo "$pkg" | awk '{print $1}'
}

# Функция для получения зависимостей пакета
get_deps() {
    local pkg="$1"
    pkg info -d $(clean_pkg_name "$pkg") 2>/dev/null | tail -n +2 | sed 's/^[[:space:]]*//' | \
    while read -r dep_line; do
        # Пропускаем пустые строки
        [ -z "$dep_line" ] && continue

        # Очищаем имя пакета
        local clean_dep=$(clean_pkg_name "$dep_line")

        # Проверяем, существует ли пакет
        if pkg info "$clean_dep" > /dev/null 2>&1; then
            echo "$dep_line"
        else
            # Если пакет не найден, пытаемся получить базовое имя
            # (для FreeBSD-clibs-15.0 -> FreeBSD-clibs)
            local base_name=$(echo "$clean_dep" | sed 's/-[0-9].*//')
            if [ -n "$base_name" ] && pkg info "$base_name" > /dev/null 2>&1; then
                echo "$dep_line"
            else
                # Если не удалось найти, выводим оригинальное имя
                echo "$dep_line"
            fi
        fi
    done
}

# Рекурсивная функция для отображения дерева
show_tree() {
    local pkg="$1"
    local indent="$2"
    local is_last="$3"
    local processed_pkgs="$4"  # Список уже обработанных пакетов
    
    # Проверяем, не обрабатывали ли мы уже этот пакет в данной ветке
    if echo "$processed_pkgs" | grep -q "^$pkg$"; then
        # Пакет уже был обработан - выводим информацию о циклической зависимости
        if [ "$is_last" = "true" ]; then
            echo "${indent}    └── [циклическая зависимость: $pkg]"
        else
            echo "${indent}│   └── [циклическая зависимость: $pkg]"
        fi
        return
    fi
    
    # Добавляем текущий пакет в список обработанных
    if [ -z "$processed_pkgs" ]; then
        processed_pkgs="$pkg"
    else
        processed_pkgs="$processed_pkgs
$pkg"
    fi

    # Определяем префиксы для отображения
    if [ "$is_last" = "true" ]; then
        local prefix="└── "
        local next_indent="$indent    "
    else
        local prefix="├── "
        local next_indent="$indent│   "
    fi

    # Выводим имя пакета или "системная зависимость"
    if [ "$SHOW_SYSTEM_DETAILS" = "true" ] || ! is_system_package "$pkg"; then
        echo "${indent}${prefix}${pkg}"
    else
        echo "${indent}${prefix}системная зависимость"
        # Для системных зависимостей не показываем дальнейшее дерево, если не включен детальный режим
        if [ "$SHOW_SYSTEM_DETAILS" = "false" ]; then
            return
        fi
    fi

    # Получаем зависимости текущего пакета
    local deps
    deps=$(get_deps "$pkg")

    if [ -z "$deps" ]; then
        # Если зависимостей нет
        if [ "$is_last" = "true" ]; then
            echo "${indent}    └── (нет зависимостей)"
        else
            echo "${indent}│   └── (нет зависимостей)"
        fi
    else
        # Обрабатываем зависимости
        local count=0
        local total=$(echo "$deps" | wc -l)

        echo "$deps" | while read -r dep; do
            count=$((count + 1))

            # Пропускаем системные зависимости, если они не в детальном режиме
            if [ "$SHOW_SYSTEM_DETAILS" = "false" ] && is_system_package "$dep"; then
                # Если это последняя зависимость и она системная
                if [ $count -eq $total ]; then
                    echo "${next_indent}└── системная зависимость"
                else
                #    echo "${next_indent}├── системная зависимость"
                fi
                continue
            fi

            if [ $count -eq $total ]; then
                # Последняя зависимость
                show_tree "$dep" "$next_indent" "true" "$processed_pkgs"
            else
                # Не последняя зависимость
                show_tree "$dep" "$next_indent" "false" "$processed_pkgs"
            fi
        done
    fi
}

# Основная часть скрипта
echo "======= Дерево зависимостей пакета $PKG_NAME ======="
#if [ "$SHOW_SYSTEM_DETAILS" = "false" ]; then
#    echo "Режим: системные зависимости скрыты"
#fi
show_tree "$PKG_NAME" "" "true" ""
