#!/bin/bash

# This is Darktable build script for Porteus
# Version 2026-08-26

# Copyright 2023-2030, Blaze, Dankov, Russia
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
#  EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
#  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

export LC_ALL=C
export XZ_OPT="-T0"
export CMAKE_BUILD_PARALLEL_LEVEL=$(nproc)
export CMAKE_POLICY_VERSION_MINIMUM=3.5
[ "$(whoami)" != "root" ] && { echo -e "\nYou need to be root to run this script.\n"; exit 1; }

PRGNAM=${PRGNAM:-darktable}
BUILD=${BUILD:-1}
ARCH=$(uname -m)
VERSION=$(lynx -head -dump "https://github.com/darktable-org/darktable/releases/latest" 2>/dev/null | grep -i Location | grep -o "[0-9].*$" | tr -d '\r')
SOURCE="https://github.com/darktable-org/darktable/releases/download/release-${VERSION}/darktable-${VERSION}.tar.xz"
BOLD="\e[1m"; CYAN="\e[96m"; GREEN="\e[92m"; RED="\e[31m"; YELLOW="\e[93m"; RESET="\e[0m"
TMPDIR=/tmp/portch; SRC="$TMPDIR/src"; PKG="$TMPDIR/package-$PRGNAM"; OUTPUT=${OUTPUT:-/tmp}; JOBS=$(nproc)
MODULES_TO_DEACTIVATE=()
INJECTED_LIBS=()

cleanup(){
    if [ ${#MODULES_TO_DEACTIVATE[@]} -gt 0 ]; then
        echo -e "\n${CYAN}Deactivating temporary modules...${RESET}"
        for mod in "${MODULES_TO_DEACTIVATE[@]}"; do
            deactivate -q "$mod" >/dev/null 2>&1
            rm -f "$mod"
        done
    fi
    rm -f /tmp/*.txz
    rm -rf "$TMPDIR"
}

die(){ echo -e "\n${RED}${BOLD}$1${RESET}\n"; cleanup; exit 1; }

build_pugixml_module(){
    local pugixml_version=$(lynx -head -dump "https://github.com/zeux/pugixml/releases/latest" 2>/dev/null | grep -i Location | grep -o "[0-9].*$" | tr -d '\r')
    [ -z "$pugixml_version" ] && pugixml_version="1.14"
    
    local pugixml_url="https://github.com/zeux/pugixml/releases/download/v${pugixml_version}/pugixml-${pugixml_version}.tar.gz"
    local pugixml_src="$TMPDIR/pugixml_src"
    local pugixml_pkg="$TMPDIR/pugixml_pkg"
    local pugixml_mod="$TMPDIR/pugixml-${pugixml_version}.xzm"
    
    echo -e "\n${CYAN}Building pugixml ${pugixml_version} module (static)...${RESET}"
    
    mkdir -p "$pugixml_src" "$pugixml_pkg"
    wget -q "$pugixml_url" -O "$TMPDIR/pugixml.tar.gz" || die "Failed to download pugixml"
    tar -xf "$TMPDIR/pugixml.tar.gz" -C "$pugixml_src" --strip-components=1 || die "Failed to extract pugixml"
    rm -f "$TMPDIR/pugixml.tar.gz"
    
    cd "$pugixml_src"
    mkdir -p build && cd build
    cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF .. || die "pugixml cmake failed"
    make -j"$JOBS" || die "pugixml build failed"
    make install DESTDIR="$pugixml_pkg" || die "pugixml install failed"
    
    dir2xzm "$pugixml_pkg" "$pugixml_mod" || die "Failed to create pugixml module"
    
    echo -e "${GREEN}pugixml module created (static, will be linked into darktable)${RESET}"
    
    PUGIXML_MOD_PATH="$pugixml_mod"
}

copy_libs_to_pkg(){
    local lib_name="$1"
    local mod_path="$2"
    local tmp_mount="$TMPDIR/mnt_${lib_name}"
    
    mkdir -p "$tmp_mount"
    
    echo -e "${CYAN}Copying ${lib_name} runtime libraries into package...${RESET}"
    
    unsquashfs -f -d "$tmp_mount" "$mod_path" >/dev/null 2>&1 || { rm -rf "$tmp_mount"; return; }
    
    find "$tmp_mount/usr/lib64" -name "*.so*" \( -type f -o -type l \) 2>/dev/null | while read lib; do
        local rel_path="${lib#$tmp_mount}"
        local dest_dir="$PKG$(dirname "$rel_path")"
        mkdir -p "$dest_dir"
        cp -a "$lib" "$dest_dir/" 2>/dev/null
    done
    
    rm -rf "$tmp_mount"
    echo -e "${GREEN}${lib_name} libraries bundled into module.${RESET}"
}

inject_deps(){
    local pkgs="potrace lensfun sqlite Imath"
    local tmp_mods="$TMPDIR/porteus_mods"
    mkdir -p "$tmp_mods"
    
    echo -e "\n${CYAN}Checking required host libraries...${RESET}"
    
    if ! pkg-config --exists pugixml 2>/dev/null && [ ! -f /usr/include/pugixml.hpp ]; then
        build_pugixml_module
        echo -e "${YELLOW}Activating pugixml module (build-time only)...${RESET}"
        if activate -q "$PUGIXML_MOD_PATH"; then
            MODULES_TO_DEACTIVATE+=("$PUGIXML_MOD_PATH")
            echo -e "${GREEN}pugixml module activated (will be statically linked).${RESET}"
        else
            die "Failed to activate pugixml module."
        fi
    else
        echo -e "${GREEN}pugixml already installed${RESET}"
    fi
    
    for pkg in $pkgs; do
        local found=0
        
        case "$pkg" in
            potrace)
                [ -f /usr/include/potracelib.h ] && found=1
                pkg-config --exists potrace 2>/dev/null && found=1
                ;;
            lensfun)
                [ -f /usr/include/lensfun/lensfun.h ] && found=1
                pkg-config --exists lensfun 2>/dev/null && found=1
                ;;
            sqlite)
                [ -f /usr/include/sqlite3.h ] && found=1
                pkg-config --exists sqlite3 2>/dev/null && found=1
                ;;
            Imath)
                [ -f /usr/include/Imath/ImathVec.h ] && found=1
                pkg-config --exists Imath 2>/dev/null && found=1
                ;;
        esac
        
        if [ "$found" -eq 0 ]; then
            echo -e "${YELLOW}${pkg} not found in system. Downloading via getmod...${RESET}"
            
            if getmod -q "$pkg"; then
                local mod_file=$(find /tmp -name "${pkg}*.xzm" -type f 2>/dev/null | head -n1)
                
                if [ -n "$mod_file" ]; then
                    local mod_basename=$(basename "$mod_file")
                    mv "$mod_file" "$tmp_mods/$mod_basename"
                    local mod_path="$tmp_mods/$mod_basename"
                    
                    echo -e "${YELLOW}Activating ${pkg} module...${RESET}"
                    if activate -q "$mod_path"; then
                        MODULES_TO_DEACTIVATE+=("$mod_path")
                        INJECTED_LIBS+=("$pkg:$mod_path")
                        echo -e "${GREEN}${pkg} module activated (will be bundled into final module).${RESET}"
                    else
                        die "Failed to activate ${pkg} module."
                    fi
                else
                    die "Failed to find downloaded module for ${pkg}."
                fi
            else
                die "Failed to download ${pkg} module via getmod."
            fi
        else
            echo -e "${GREEN}${pkg} already in system (no need to bundle).${RESET}"
        fi
    done
    
    echo -e "${GREEN}All required dependencies are present.${RESET}"
}

fix_desktop_icon(){
    local desktop_file="$PKG/usr/share/applications/org.darktable.darktable.desktop"
    
    if [ -f "$desktop_file" ]; then
        sed -i 's|^Icon=darktable$|Icon=/usr/share/icons/hicolor/256x256/apps/darktable.png|' "$desktop_file"
        echo -e "${GREEN}Desktop file icon path fixed.${RESET}"
    fi
}

clean_pkg(){
    echo -e "\n${CYAN}Cleaning package from unnecessary files...${RESET}"
    
    rm -f "$PKG/usr/lib64/libpugixml.a"
    rm -f "$PKG/usr/include/pugixml.hpp"
    rm -f "$PKG/usr/include/pugiconfig.hpp"
    rm -rf "$PKG/usr/lib64/cmake/pugixml"
    
    rm -rf "$PKG/usr/share/man"
    rm -rf "$PKG/usr/share/doc"
    rm -rf "$PKG/usr/share/metainfo"
    
    # Remove Python bindings for Imath (python version detected dynamically)
    local pyver=$(python3 -c 'import sys; print("%d.%d" % sys.version_info[:2])' 2>/dev/null)
    if [ -n "$pyver" ]; then
        rm -rf "$PKG/usr/lib64/python${pyver}"
    else
        rm -rf "$PKG"/usr/lib64/python3.*
    fi
    rm -f "$PKG/usr/lib64/libPyImath"*
    
    rm -f "$PKG/usr/share/darktable/pswp/LICENSE"
    
    rmdir "$PKG/usr/include" 2>/dev/null
    rmdir "$PKG/usr/lib64/cmake" 2>/dev/null
    
    echo -e "${GREEN}Package cleaned.${RESET}"
}

setup_locale(){
    local ldir="$PKG/usr/share/locale"
    local lua_ldir="$PKG/usr/share/darktable/lua-scripts/locale"
    [ ! -d "$ldir" ] && return 0
    
    echo -e "\n${CYAN}Darktable locale setup${RESET}"
    
    local locales=($(find "$ldir" -mindepth 1 -maxdepth 1 -type d -printf '%f\n' 2>/dev/null | sort))
    local count=${#locales[@]}
    [ "$count" -eq 0 ] && { echo -e "${RED}warn: no locales found${RESET}"; return 0; }
    
    echo -e "Available locales ($count):"
    local i=1
    for loc in "${locales[@]}"; do
        printf "  %2d) %-15s" "$i" "$loc"
        [ $((i % 5)) -eq 0 ] && echo
        i=$((i + 1))
    done
    [ $((count % 5)) -ne 0 ] && echo
    
    local choice
    while true; do
        echo
        read -p "Locale number to keep (English always kept) [1-$count, Enter=English only]: " choice
        if [ -z "$choice" ]; then
            find "$ldir" -mindepth 1 -maxdepth 1 -type d -not -name "en*" -exec rm -rf {} +
            if [ -d "$lua_ldir" ]; then
                rm -rf "$lua_ldir"
                echo -e "${CYAN}info: lua-scripts locale directory removed completely${RESET}"
            fi
            echo -e "${GREEN}info: only English kept${RESET}"
            return 0
        fi
        [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "$count" ] && break
        echo -e "${RED}warn: invalid input, try again${RESET}"
    done
    
    local target="${locales[$((choice-1))]}"
    local base_lang="${target%%_*}"
    echo -e "${CYAN}Removing all locales except English and $target...${RESET}"
    find "$ldir" -mindepth 1 -maxdepth 1 -type d -not -name "en*" -not -name "$target" -exec rm -rf {} +
    
    if [ -d "$lua_ldir" ]; then
        local before_count=$(find "$lua_ldir" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l)
        find "$lua_ldir" -mindepth 1 -maxdepth 1 -type d -not -name "en*" -not -name "${base_lang}*" -exec rm -rf {} +
        local after_count=$(find "$lua_ldir" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l)
        
        if [ "$after_count" -eq 0 ]; then
            rm -rf "$lua_ldir"
            echo -e "${CYAN}info: no matching lua-scripts locales found, directory removed${RESET}"
        else
            local kept_locales=$(find "$lua_ldir" -mindepth 1 -maxdepth 1 -type d -printf '%f ' 2>/dev/null)
            echo -e "${CYAN}info: kept $after_count/$before_count lua-scripts locales: ${kept_locales}${RESET}"
        fi
    fi
    
    echo -e "${GREEN}info: kept: en + $target${RESET}"
}

[ -z "$VERSION" ] && die "Could not detect latest $PRGNAM version."

[ -f "/usr/bin/darktable" ] && MYVER=$(basename /var/lib/pkgtools/packages/darktable* 2>/dev/null | cut -d'-' -f2)
[ "$MYVER" == "$VERSION" ] && { echo -e "You have the latest ${GREEN}$MYVER${RESET} version of $PRGNAM"; exit 0; }

read -p "$(echo -e Would you like to build $PRGNAM ${GREEN}$VERSION${RESET} xzm module? [y/n])" -n 1 -r -s && echo
[[ $REPLY =~ ^[Yy]$ ]] || exit 0

rm -rf "$TMPDIR" && mkdir -p "$SRC" "$PKG/usr/bin" "$PKG/usr/share/applications"
cd "$TMPDIR"

inject_deps

echo -e "\nDownloading ${CYAN}${BOLD}${PRGNAM}-${VERSION}${RESET}"

if wget -q "$SOURCE" -O "$TMPDIR/$PRGNAM.tar.xz"; then
    tar -xf "$TMPDIR/$PRGNAM.tar.xz" -C "$SRC" --strip-components=1 || die "Failed to extract"
    rm -f "$TMPDIR/$PRGNAM.tar.xz"
else
    git clone --depth 1 --recursive --shallow-submodules --branch "release-${VERSION}" https://github.com/darktable-org/darktable.git "$SRC" 2>/dev/null || {
        rm -rf "$SRC"
        git clone --depth 1 --recursive --branch "release-${VERSION}" https://github.com/darktable-org/darktable.git "$SRC" || die "git clone failed"
    }
fi

[ -f "$SRC/CMakeLists.txt" ] && [ -d "$SRC/src" ] || die "Source validation failed."

cd "$SRC" && mkdir -p build && cd build

CMAKE_OPTS=(
    -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release
    -DUSE_OPENCL=ON -DTESTBUILD_OPENCL_PROGRAMS=OFF
    -DUSE_WEBP=ON
    -DUSE_OPENEXR=OFF -DUSE_JXL=OFF -DUSE_AVIF=OFF -DUSE_HEIF=OFF -DUSE_OPENJPEG=OFF
    -DUSE_ICU=ON
    -DUSE_CAMERA_SUPPORT=ON
    -DBUILD_PRINT=OFF
    -DUSE_MAP=OFF -DUSE_AI=OFF -DUSE_GMIC=OFF
    -DUSE_GRAPHICSMAGICK=OFF -DUSE_IMAGEMAGICK=OFF
    -DUSE_PORTMIDI=OFF -DUSE_COLORD=OFF
    -DDONT_USE_INTERNAL_LUA=OFF -DUSE_LUA=ON
    -DUSE_BUNDLED_PUGIXML=ON -DALLOW_DOWNLOADING_PUGIXML=ON
    -DUSE_LIBRAW=ON -DDONT_USE_INTERNAL_LIBRAW=OFF
    -DSOURCE_PACKAGE=OFF -DBINARY_PACKAGE_BUILD=ON -Wno-dev
    -DBUILD_TESTING=OFF -DBUILD_CMSTEST=OFF
)

cmake -G Ninja "${CMAKE_OPTS[@]}" .. || die "CMake configuration failed."
ninja -j"$JOBS" || die "Compilation failed."
DESTDIR="$PKG" ninja install || die "Installation failed."

[ -f "$PKG/usr/bin/darktable" ] || die "Build failed: darktable binary not found."

setup_locale

if [ ${#INJECTED_LIBS[@]} -gt 0 ]; then
    echo -e "\n${CYAN}Bundling injected runtime dependencies into module...${RESET}"
    for entry in "${INJECTED_LIBS[@]}"; do
        if [[ "$entry" == *":"* ]]; then
            lib_name="${entry%%:*}"
            mod_path="${entry#*:}"
            copy_libs_to_pkg "$lib_name" "$mod_path"
        fi
    done
fi

clean_pkg
fix_desktop_icon

find "$PKG" -type f \( -path '*/bin/*' -o -path '*/libexec/*' -o -name '*.so' -o -name '*.so.*' \) -print0 | xargs -0 -r -P "$JOBS" strip --strip-unneeded 2>/dev/null || true

rm -rf "$SRC"
cd "$PKG"

mkdir -p "$PKG/var/lib/pkgtools/packages"
{
    echo "PACKAGE NAME: $PRGNAM-$VERSION-$ARCH"
    cat << EOM
PACKAGE DESCRIPTION:
darktable: darktable (photography workflow application)
darktable:
darktable: darktable is an open source photography workflow 
darktable: application and raw developer.
darktable:
darktable: https://www.darktable.org/
darktable:
FILE LIST:
EOM
    find * | grep -v var
} > "$PKG/var/lib/pkgtools/packages/$PRGNAM-$VERSION-$ARCH"

mkdir -p "$OUTPUT"
dir2xzm "$PKG" "$OUTPUT/$PRGNAM-$VERSION-$ARCH-$BUILD.xzm"

[ -f "$OUTPUT/${PRGNAM}-${VERSION}-${ARCH}-${BUILD}.xzm" ] && \
    echo -e "\n${BOLD}Your $PRGNAM module is at: ${GREEN}${BOLD}$OUTPUT/$PRGNAM-$VERSION-${ARCH}-${BUILD}.xzm${RESET}\n${BOLD}Please copy it to your modules folder to survive a reboot.${RESET}\n" || \
    echo -e "\n${RED}${BOLD}Failed. Your $PRGNAM module is not built.${RESET}\n"

cleanup
exit 0
