#!/bin/sh
#
# Copyright (C) 2024  Etersoft
# Copyright (C) 2024  Ivan Mazhukin <vanomj@etersoft.ru>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
json=0

is_de_exist() {
    local json_file="$(realpath $epm_vardir/desktop.d/$1.json)"
    local de_name=$1

    if [ -f "$json_file" ]; then
        return 0 
    else
        message "Error: Manifest for '$de_name' not found."
        exit 1  
    fi
}

copy_files_if_absent() {
    local source_dir="$CONFIGDIR/desktop.d/"
    local target_dir="$epm_vardir/desktop.d"

    sudorun mkdir -p "$target_dir"

    for file in "$source_dir"/*.json; do
        filename=$(basename "$file")
        target_file="$target_dir/$filename"

        if [ ! -f "$target_file" ]; then
           sudorun cp "$file" "$target_file"
        fi
    done
}

check_installed_des() {
    for json_file in $epm_vardir/desktop.d/*.json; do
        de_name=$(basename "$json_file" .json)
        dependencies=$(get_value "$de_name" "dependencies")
        
        is_installed "$dependencies" && status=true || status=false
        update_installed_status $de_name $status
    done
}

is_installed() {
    local dependencies=$1
    epm installed $dependencies > /dev/null 2>&1
    return
}

check_and_update_version() {
    for json_file in $epm_vardir/desktop.d/*.json; do
        de_name=$(basename "$json_file" .json)
        main_package=$(get_value "$de_name" dependencies | awk '{print $1}')
        
        current_version=$(get_value "$de_name" version)
        repo_version=$(get_repo_version "$main_package")

        if [ "$repo_version" != "Version unchanged" ] && [ -n "$repo_version" ] && [ "$repo_version" != "$current_version" ]; then
            update_json_version "$de_name" "$repo_version"
        fi

    done
}

update_installed_status() {
    local de_name=$1
    local status=$2
    local json_file="$(realpath $epm_vardir/desktop.d/$de_name.json)"

 
    sudorun sed -i "s/\"installed\": .*/\"installed\": $status,/" "$json_file"
}

update_json_version() {
    local de_name=$1
    local new_version=$2
    local json_file="$epm_vardir/desktop.d/$de_name.json"

    sudorun sed -i "s/\"version\": \".*\"/\"version\": \"$new_version\"/" "$json_file"
}

get_value() {
    local json_file="$(realpath $epm_vardir/desktop.d/$1.json)"
    local key="$2"

    if [ "$key" = "description" ]; then
        cat "$json_file" | epm --quiet tool json -b  | grep "\[\"$key\"" | cut -d ' ' -f2- | sed 's/[",]//g'
    else
        cat "$json_file" | epm --quiet tool json -b  | grep "\[\"$key\"" | awk '{print $2}' | sed 's/[",]//g' | tr '\n' ' '
    fi
}

get_repo_version() {
    local package_name=$1
    local latest_version

    latest_version=$(eget --quiet -O- "https://rdb.altlinux.org/api/package/package_info?name=$package_name&arch=x86_64&source=false&branch=sisyphus&full=false" \
        | epm --quiet tool json -b | grep '"packages",0,"version"]' | awk '{print $2}' | tr -d '"')

    if [ -n "$latest_version" ]; then
        echo "$latest_version"
    else
        latest_version=$(epm --quiet info $package_name | grep 'Version:' | awk '{print $2}' | sed 's/-.*//') 

        if [ -n "$latest_version" ]; then
            echo "$latest_version"
        else
            echo "Version unchanged"
        fi
    fi
}

install_de() {
    local de_name=$1

    dependencies=$(get_value "$de_name" "dependencies")

    if is_installed "$dependencies"; then
        message "$de_name is already installed."
        return 0
    fi

    message "Installing $de_name with dependencies: $dependencies"
    
    if epm install $dependencies; then
        message "$de_name successfully installed."
        update_installed_status "$de_name" true
    else
        message "Failed to install $de_name."
        return 1
    fi
}

remove_de() {
    local de_name=$1

    dependencies=$(get_value "$de_name" "dependencies")

    if ! is_installed "$dependencies"; then
        message "$de_name is not installed."
        return 0
    fi

    message "Removing $de_name with dependencies: $dependencies"

    if epm remove $dependencies; then
        message "$de_name successfully removed."
        update_installed_status "$de_name" false
    else
        message "Failed to remove $de_name."
        return 1
    fi
}

get_de_info() {
    local de_name=$1
    message "   Information for $de_name:
    Name: $(get_value $de_name name)
    Version: $(get_value $de_name version)
    Installed: $(get_value $de_name installed)
    Description: $(get_value $de_name description)"
}

list_des() {
    if [ "$json" -eq 1 ]; then
        echo '['
        first=1
        for de in $epm_vardir/desktop.d/*.json; do
            if [ $first -eq 1 ]; then
                first=0
            else
                echo ','
            fi
            cat "$de"
        done
        echo ']'
    else
        for de in $epm_vardir/desktop.d/*.json; do
            basename "$de" .json
        done
    fi
}

show_help() {
    message 'Usage: epm desktop [command]
Commands:
    install [de_name]    Install a desktop environment
    remove [de_name]     Remove a desktop environment
    info [de_name]       Get information about a desktop environment
    list                 List all available desktop environments'
}

epm_desktop() {
    copy_files_if_absent

    check_installed_des
    check_and_update_version

    case "$2" in
        --json)
            json=1
            ;;
    esac

    case "$1" in
        install)
            is_de_exist "$2"
            install_de "$2"
            ;;
        remove)
            is_de_exist "$2"
            remove_de "$2"
            ;;
        info)
            is_de_exist "$2"
            get_de_info "$2"
            ;;
        list)
            list_des
            ;;
        *)
            show_help
            ;;
    esac
}
