#!/bin/bash
# Generate per-package file listings for multi-package dune projects
# Usage: ocaml-find-files-multi [pkg1 pkg2 pkg3 ...]
# If no packages specified, auto-detects from .install files or installed directories
# Creates: ocaml-files.runtime.<pkg>, ocaml-files.devel.<pkg>
#
# Environment variables (set by %ocaml_find_files_multi macro):
#   OCAMLDIR  - path to ocaml library directory
#   BINDIR    - path to bin directory (default: /usr/bin)
#   DATADIR   - path to share directory (default: /usr/share)
#   BUILDROOT - buildroot prefix (default: empty)

if [ -z "$OCAMLDIR" ]; then
    # Detect libdir based on architecture
    if [ -d /usr/lib64 ]; then
        OCAMLDIR=/usr/lib64/ocaml
    else
        OCAMLDIR=/usr/lib/ocaml
    fi
fi

BINDIR="${BINDIR:-/usr/bin}"
DATADIR="${DATADIR:-/usr/share}"
BUILDROOT="${BUILDROOT:-}"

parse_install_file() {
    local install_file="$1"
    local pkg="$2"
    local runtime_file="ocaml-files.runtime.$pkg"
    local devel_file="ocaml-files.devel.$pkg"

    : >"$runtime_file"
    : >"$devel_file"

    local section=""
    local seen_dirs=""

    while IFS= read -r line; do
        # Trim whitespace
        line="${line#"${line%%[![:space:]]*}"}"
        line="${line%"${line##*[![:space:]]}"}"

        case "$line" in
            lib:*|libexec:*|bin:*|share:*|doc:*|stublibs:*|etc:*|man:*)
                section="${line%%:*}"
                ;;
            "["*|"]"*|"")
                continue
                ;;
            \"*)
                # Extract source path
                local src="${line#\"}"
                src="${src%%\"*}"

                # Extract destination (if specified with {"dest"})
                local dest
                if [[ "$line" == *'{"'* ]]; then
                    dest="${line#*\{\"}"
                    dest="${dest%%\"*}"
                else
                    dest="${src##*/}"
                fi

                # Remove leading ? from dest (optional marker)
                dest="${dest#\?}"

                case "$section" in
                    lib)
                        local destpath="$OCAMLDIR/$pkg/$dest"
                        local destdir="${destpath%/*}"

                        # Add directory entry if not seen
                        if [[ "$seen_dirs" != *"|$destdir|"* ]]; then
                            seen_dirs="$seen_dirs|$destdir|"
                            echo "%dir $destdir" >>"$runtime_file"
                        fi

                        case "$dest" in
                            *.cmo|*.cma|*.cmi|*.so|*.js)
                                echo "$destpath" >>"$runtime_file"
                                ;;
                            *.a|*.o|*.cmt|*.cmti|*.cmx|*.cmxa|*.ml|*.mli|META|opam|dune-package)
                                echo "$destpath" >>"$devel_file"
                                ;;
                            *)
                                echo "$destpath" >>"$devel_file"
                                ;;
                        esac
                        ;;
                    libexec)
                        local destpath="$OCAMLDIR/$pkg/$dest"
                        case "$dest" in
                            *.cmxs)
                                echo "$destpath" >>"$runtime_file"
                                ;;
                            *)
                                echo "$destpath" >>"$devel_file"
                                ;;
                        esac
                        ;;
                    stublibs)
                        echo "$OCAMLDIR/stublibs/$dest" >>"$runtime_file"
                        ;;
                    bin)
                        echo "$BINDIR/$dest" >>"$runtime_file"
                        ;;
                    share)
                        echo "$DATADIR/$pkg/$dest" >>"$runtime_file"
                        ;;
                    man)
                        # Man files are compressed by RPM, use wildcard
                        # Extract path relative to man/ (e.g., man1/foo.1)
                        local manpath="${src##*/man/}"
                        echo "%_mandir/$manpath*" >>"$runtime_file"
                        ;;
                    doc)
                        # Skip doc files
                        ;;
                esac
                ;;
        esac
    done <"$install_file"
}

find_files_fallback() {
    local pkg="$1"
    local pkgdir="$BUILDROOT$OCAMLDIR/$pkg"

    if [ -d "$pkgdir" ]; then
        echo "Using find for $pkg file listing (no .install file)"

        find "$pkgdir" -type f -regextype posix-extended \( \
            -regex '.*\.(cmo|cma|cmi|cmxs|so|js)$' \
            \) -printf "$OCAMLDIR/$pkg/%P\n" >"ocaml-files.runtime.$pkg"

        find "$pkgdir" -type d -printf "%%dir $OCAMLDIR/$pkg/%P\n" >>"ocaml-files.runtime.$pkg"

        find "$pkgdir" -type f -regextype posix-extended \( \
            -regex '.*\.(a|o|cmt|cmti|cmx|cmxa|ml|mli|exe)$' \
            -o -name 'META' \
            -o -name 'opam' \
            -o -name 'dune-package' \
            \) -printf "$OCAMLDIR/$pkg/%P\n" >"ocaml-files.devel.$pkg"
    else
        echo "Warning: package $pkg not found (no .install file or directory)" >&2
        : >"ocaml-files.runtime.$pkg"
        : >"ocaml-files.devel.$pkg"
    fi
}

# Main logic
pkglist="$*"

if [ -z "$pkglist" ]; then
    if ls _build/default/*.install >/dev/null 2>&1; then
        pkglist=$(ls _build/default/*.install 2>/dev/null | xargs -n1 basename | sed 's/\.install$//')
    else
        pkglist=$(find "$BUILDROOT$OCAMLDIR" -mindepth 1 -maxdepth 1 -type d -printf '%f ')
    fi
fi

for pkg in $pkglist; do
    install_file="_build/default/$pkg.install"
    if [ -f "$install_file" ]; then
        echo "Using $install_file for $pkg file listing"
        parse_install_file "$install_file" "$pkg"
    else
        find_files_fallback "$pkg"
    fi
done
