#!/usr/bin/env bash

if command -v doas >/dev/null; then
    su=doas
elif command -v sudo >/dev/null; then
    su=sudo
else
    echo "[ERROR] Cannot get root access"
    exit 1
fi

set -euo pipefail

VERSION="0.0.3-leviticus"

PKGIT_LOC=$(dirname "$(readlink -f "${BASH_SOURCE}")")
PKGIT_SCRIPT="$PKGIT_LOC/$(basename "${BASH_SOURCE[0]}")"

ROOT="/var/lib/pkgit"
BIN_DIR="/usr/local/bin"
LIB_DIR="/usr/lib"
INCLUDE_DIR="/usr/include"
PKGS_DIR="$ROOT/pkgs"
BUILD_DIR="$ROOT/build"

BLDIT_DIR="/etc/pkgit/bldit"
USER_REPOS_DIR="/etc/pkgit/repos"

PKGIT_ESSENTIAL_DIRS=(
    "$ROOT"
    "$BIN_DIR"
    "$LIB_DIR"
    "$INCLUDE_DIR"
    "$PKGS_DIR"
    "$BUILD_DIR"
)

PKGIT_CONFIG_DIRS=(
    "$BLDIT_DIR"
    "$USER_REPOS_DIR"
)

red='\033[0;31m'
green='\033[0;32m'
yellow='\033[0;33m'
blue='\033[0;34m'
magenta='\033[0;35m'
cyan='\033[0;36m'
gray='\033[0;37m'
bold_red='\033[1;31m'
bold_green='\033[1;32m'
bold_yellow='\033[1;33m'
bold_blue='\033[1;34m'
bold_magenta='\033[1;35m'
bold_cyan='\033[1;36m'
bold_gray='\033[1;37m'
reset='\033[0m'

color() {
    echo "${1}$2${reset}"
}

echo_pkgit() {
    echo -e "$(color "$yellow" "[")$(color "$magenta" "pkgit")$(color "$yellow" "]")"
}

echo_success() {
    echo -e $(color "$green" "[SUCCESS]")
}

or() {
    color "$yellow" "|"
}

exmpl() {
    color "$blue" "$1"
}

shortopt() {
    if [ $# == 2 ]; then
        echo "$(color "$bold_green" "$1") $(exmpl "$2")"
    else
        color "$bold_green" "$1"
    fi
}

longopt() {
    if [ $# == 2 ]; then
        echo "$(color "$cyan" "$1") $(exmpl "$2")"
    else
        color "$cyan" "$1"
    fi
}

desc() {
    color "$gray" "$1"
}

autogen() {
    if ((EUID != 0)); then
        exec "$su" "$0" "$@"
    fi
    for dir in "${PKGIT_ESSENTIAL_DIRS[@]}"; do
        if [ ! -d "$dir" ]; then
            mkdir -p "$dir"
            echo -e "$(echo_pkgit) successfully generated $dir"
        fi
    done
    for dir in "${PKGIT_CONFIG_DIRS[@]}"; do
        if [ ! -d "$dir" ]; then
            mkdir -p "$dir"
            echo -e "$(echo_pkgit) successfully generated $dir"
        fi
    done
}

repo_from_git() {
    local url="$1"
    local req_tag="${2:-}"
    local pkg=$(basename "$url" .git | tr '[:upper:]' '[:lower:]')

    local tags
    if [[ -n "$req_tag" ]]; then
        tags="$req_tag"
    else
        tags=$(git ls-remote --tags --refs "$url" 2>/dev/null |
            awk -F/ '{print $3}' |
            grep -E '^[0-9]+(\.[0-9]+)*$|^v[0-9]+(\.[0-9]+)*$' |
            sort -Vr |
            head -n 1) || {
            echo -e "$(echo_pkgit) $(color "$yellow" "[WARNING]") Could not fetch tags from $url" >&2
            tags="HEAD"
        }
        [[ -n "$tags" ]] || tags="HEAD"
    fi

    local latest_tag
    latest_tag=$(echo "$tags" | head -n 1)

    touch "$USER_REPOS_DIR/repos"
    if [[ ! $(grep "$url" "$USER_REPOS_DIR/repos") ]] ||
        [[ ! $(grep "${url%.git}" "$USER_REPOS_DIR/repos") ]]; then
        echo "$pkg $url" | tee -a "$USER_REPOS_DIR/repos" >/dev/null
    fi

    echo "$latest_tag"
}

add_repo_pkg() {
    [[ -z "${1:-}" ]] && {
        echo "Usage: pkgit arp <raw-file-url>"
        exit 1
    }
    if [[ "$1" == http* ]]; then
        file=$(curl "$1")
    else
        file=$(cat "$1")
    fi
    for url in $file; do
        repo_from_git "$url"
    done
}

sync() {
    echo -e "$(color "$magenta" "[pkgit]") Syncing repositories..."
    if [ -z "${2:-}" ]; then
        files=("$USER_REPOS_DIR"/*)
        echo ${files[@]}
        for file in "${files[@]}"; do
            while IFS= read -r repo; do
                echo ""
                echo -e "$(echo_pkgit) $(color "$blue" "[REPO]") Syncing: $(color "$green" "$repo")"
                repo_from_git "$repo"
                echo -e "$(echo_pkgit) $(echo_success) Sync completed for: $(color "$green" "$repo")"
            done <"$file"
        done
    else
        while IFS= read -r repo; do
            echo ""
            echo -e "$(echo_pkgit) $(color "$blue" "Syncing:") $(color "$green" "$repo")"
            repo_from_git "$repo"
            echo -e "$(echo_pkgit) $(color "$blue" "Sync completed for:") $(color "$green" "$repo")"
        done <"$USER_REPOS_DIR/${2:-*}"
    fi
    echo ""
    echo -e "$(echo_pkgit) $(echo_success) Sync completed."
}

build_sh() {
    set -euo pipefail

    PKGIT_GIT_URL="$1"
    pkg="$2"
    tag="$3"
    BUILD_DIR="$4"
    BIN_DIR="$5"
    PKGS_DIR="$6"
    INSTALL_DIR="$PKGS_DIR/$pkg/$tag"
    SRC_DIR="$BUILD_DIR/$pkg-$tag"
    : "${BLDIT_DIR:=/etc/pkgit/bldit}"

    rm -rf "$SRC_DIR"

    if [[ "$tag" == "HEAD" ]]; then
        git -c advice.detachedHead=false clone --depth 1 "$PKGIT_GIT_URL" "$SRC_DIR"
    else
        git -c advice.detachedHead=false clone --branch "$tag" --depth 1 "$PKGIT_GIT_URL" "$SRC_DIR"
    fi

    cd "$SRC_DIR" || {
        echo "Failed to cd to $SRC_DIR" >&2
        exit 1
    }

    trust_and_source() {
        local script="$1"
        if [[ "${PKGIT_TRUST-all}" == "yes" ]]; then
            source "$script"
            return 0
        fi
        echo "Script content for review: $script"
        echo ""
        echo "# --- START --- #"
        echo ""
        cat "$script"
        echo ""
        echo "# --- END --- #"
        echo ""
        read -rp "Do you trust this script? (y/N): " answer
        [[ "$answer" =~ [Yy] ]] && source "$script"
    }

    load_dependencies() {
        DEPS=()
        if [[ -f "/etc/pkgit/deps/$pkg.sh" ]]; then
            trust_and_source "/etc/pkgit/deps/$pkg.sh" || DEPS=()
        elif [[ -f "deps.sh" ]]; then
            chmod +x deps.sh
            trust_and_source "deps.sh" || DEPS=()
        fi
    }
    install_dependencies() {
        for dep in "${DEPS[@]:-}"; do
            [[ -z "$dep" ]] && continue
            url=$(awk '{print $1}' <<<"$dep")
            ver=$(awk '{print $2}' <<<"$dep")
            depname=$(basename "$url" .git | tr '[:upper:]' '[:lower:]')
            if [[ -n "$ver" ]]; then
                $PKGIT_SCRIPT ar "$url" "$ver"
                $PKGIT_SCRIPT i "$depname:$ver"
            else
                $PKGIT_SCRIPT ar "$url"
                $PKGIT_SCRIPT i "$depname"
            fi
        done
    }

    copy_all_files() {
        mkdir -p "$INSTALL_DIR"
        find . -type f \( -executable -o -name "*.so*" -o -name "*.a" -o -name "*.h" -o -name "*.hpp" -o -name "*.c" -o -name "*.cpp" \) \
            -exec cp --parents -p {} "$INSTALL_DIR" \;
    }

    symlink_install() {
        find "$INSTALL_DIR" -type f -executable -exec ln -sf {} "$BIN_DIR" \;

        mkdir -p /usr/local/lib
        find "$INSTALL_DIR" -type f \( -name "*.so*" -o -name "*.a" \) -exec ln -sf {} /usr/local/lib/ \;

        mkdir -p /usr/local/include
        find "$INSTALL_DIR" -type f \( -name "*.h" -o -name "*.hpp" \) -exec ln -sf {} /usr/local/include/ \;

        command -v ldconfig >/dev/null && $su ldconfig || true
    }

    make_build() {
        make -j"$(nproc)"
        make install PREFIX="$INSTALL_DIR"
    }
    cmake_build() {
        mkdir -p build && cd build
        cmake -DCMAKE_INSTALL_PREFIX="$INSTALL_DIR" ..
        make -j"$(nproc)"
        make install
        cd ..
    }
    cargo_build() {
        cargo build --release
        mkdir -p "$INSTALL_DIR/bin"
        cp -r target/release/* "$INSTALL_DIR"
    }
    zig_build() {
        zig build -Dprefix="$INSTALL_DIR"
        zig build install
    }
    meson_build() {
        meson setup build --prefix="$INSTALL_DIR"
        meson compile -C build
        meson install -C build
    }
    ninja_build() {
        ninja
        ninja install
    }
    scons_build() {
        scons prefix="$INSTALL_DIR"
        scons install prefix="$INSTALL_DIR"
    }
    autogen_build() {
        ./autogen.sh --prefix="$INSTALL_DIR"
        make -j"$(nproc)"
        make install
    }
    autotools_build() {
        ./configure --prefix="$INSTALL_DIR"
        make
        make install
    }
    gradle_build() {
        gradle build
        mkdir -p "$INSTALL_DIR/libs"
        cp build/libs/* "$INSTALL_DIR/libs/"
    }
    cabal_build() {
        cabal update
        cabal install --only-dependencies
        cabal configure --prefix="$INSTALL_DIR" -fembed_data_files
        cabal build
    }
    bazel_build() { bazel build //:all; }
    buck_build() { buck build //...; }
    pants_build() { pants build ::; }
    nix_flake_build() {
        nix build
        mkdir -p "$INSTALL_DIR"
        cp -r ./result/* "$INSTALL_DIR/"
    }
    nix_build() {
        nix-build
        mkdir -p "$INSTALL_DIR"
        cp -r ./result/* "$INSTALL_DIR/"
    }
    sbt_build() {
        sbt compile
        sbt publishLocal
    }
    pnpm_build() {
        curl -fsSL https://get.pnpm.io/install.sh | sh -
        export PATH="$HOME/.local/share/pnpm:$PATH"
        pnpm install
        pnpm run build || exit 1
        mkdir -p "$INSTALL_DIR"
        cp -r dist/* "$INSTALL_DIR"
    }
    esbuild_build() { esbuild --outdir="$INSTALL_DIR"; }
    webpack_build() { webpack --output-path "$INSTALL_DIR"; }
    conan_build() {
        conan install . --install-folder build --build=missing
        conan build . --build-folder build
    }
    earthly_build() { earthly --build-arg INSTALL_DIR="$INSTALL_DIR" +default; }
    dagger_build() { dagger do build; }

    declare -A BUILD_SYSTEM_MAP=(
        ["autogen.sh"]=autogen_build
        ["Makefile"]=make_build
        ["CMakeLists.txt"]=cmake_build
        ["Cargo.toml"]=cargo_build
        ["build.zig"]=zig_build
        ["meson.build"]=meson_build
        ["build.ninja"]=ninja_build
        ["SConstruct"]=scons_build
        ["configure.ac"]=autotools_build
        ["configure"]=autotools_build
        ["build.gradle"]=gradle_build
        ["cabal.project"]=cabal_build
        ["BUILD"]=bazel_build
        ["WORKSPACE"]=bazel_build
        ["BUCK"]=buck_build
        ["pants.toml"]=pants_build
        ["pants.ini"]=pants_build
        ["pants.yaml"]=pants_build
        ["flake.nix"]=nix_flake_build
        ["default.nix"]=nix_build
        ["build.sbt"]=sbt_build
        ["pnpm-lock.yaml"]=pnpm_build
        ["esbuild.config.js"]=esbuild_build
        ["esbuild.config.ts"]=esbuild_build
        ["webpack.config.js"]=webpack_build
        ["conanfile.txt"]=conan_build
        ["conanfile.py"]=conan_build
        ["Earthfile"]=earthly_build
        ["dagger.hcl"]=dagger_build
        ["dagger.yaml"]=dagger_build
    )

    detect_and_dispatch() {
        for file in "${!BUILD_SYSTEM_MAP[@]}"; do
            if [[ -f "$file" ]]; then
                echo "Detected build system: $file"
                ${BUILD_SYSTEM_MAP[$file]}
                return 0
            fi
        done
        echo "[pkgit] No recognized build system in $SRC_DIR" >&2
        exit 1
    }

    load_dependencies
    install_dependencies

    if [[ -f "./bldit" ]]; then
        trust_and_source "./bldit" || {
            echo "Failed to source bldit"
            exit 1
        }
        copy_all_files
    elif [[ -f "$BLDIT_DIR/$pkg" ]]; then
        source "$BLDIT_DIR/$pkg" || {
            echo "Failed to source bldit"
            exit 1
        }
        bldit || {
            echo "bldit build failed"
            exit 1
        }
        copy_all_files
    else
        detect_and_dispatch
        copy_all_files
    fi

    symlink_install

    echo "Build and install completed successfully."
}

check_repo_for_pkg() {
    local pkg="$1"
    local repos=()
    local count=0

    while IFS= read -r repo_line; do
        repos+=("$repo_line")
        ((count++))
    done < <(grep "^$pkg " "$USER_REPOS_DIR/repos")

    if ((count == 0)); then
        echo "No packages found for: $pkg" >&2
        return 1
    elif ((count == 1)); then
        echo "${repos[0]}"
        return 0
    fi

    echo "Multiple packages found for '$pkg':"
    PS3="Enter the number of the package to use (1-$count), or Ctrl+C to cancel: "

    select choice in "${repos[@]}"; do
        if [[ -n "$choice" ]]; then
            echo "$choice"
            return 0
        else
            echo "Invalid selection."
        fi
    done
}

install_pkg() {
    local input="$1"
    local pkg url ver selected

    if [[ "$input" == *:* ]]; then
        pkg="${input%%:*}"
        url=$(grep "^$pkg " "$USER_REPOS_DIR/repos" | awk '{print $2}')
        ver="${input##*:}"
    else
        pkg="$input"
        selected=$(check_repo_for_pkg "$pkg") || {
            echo "Package selection cancelled or failed."
            return 1
        }

        pkg=$(awk '{print $1}' <<<"$selected" | tr -d '\r\n')
        url=$(awk '{print $2}' <<<"$selected" | tr -d '\r\n')

        url="${url#packages}"

        url="${url#"${url%%[![:space:]]*}"}"

        ver=$(repo_from_git "$url")
    fi

    #    echo "version: $ver"
    #    echo "url: $url"
    #    echo "pkg: $pkg"

    rm -rf "${BUILD_DIR:?}/${pkg}-"*

    if [ -d "${PKGS_DIR:?}/$pkg/$ver" ]; then
        echo "$pkg:$ver already installed."
        local pkg_installed=true
    else
        local pkg_installed=false
    fi

    if [ "$pkg_installed" = false ]; then
        if [[ ! -f "$BLDIT_DIR/$pkg" ]]; then
            echo -e "$(echo_pkgit) using default bldit for $pkg:$ver"
        fi

        echo -e "$(echo_pkgit) Installing $pkg:$ver ..."

        rm -rf "$BUILD_DIR/$pkg*"
        local build_dir="${BUILD_DIR:?}/${pkg}-${ver}-$(date +%s)"
        rm -rf "$build_dir"
        mkdir -p "$build_dir"
        export ROOT PKGS_DIR BIN_DIR BUILD_DIR="$build_dir"

        local bldit_args=(
            "$url"
            "$pkg"
            "$ver"
            "$BUILD_DIR"
            "$BIN_DIR"
            "$PKGS_DIR"
        )

        #        echo """
        #    url: $url
        #    pkg: $pkg
        #    ver: $ver
        #    bin-dir: $BIN_DIR
        #    pkg-dir: $PKGS_DIR
        #    build-dir: $BUILD_DIR
        #    """

        default_bldit() {
            build_sh "${bldit_args[@]}"
        }

        default_bldit || {
            echo -e "$(echo_pkgit) Build FAILED for $pkg:$ver"
            return 1
        }
        echo -e "$(echo_pkgit) Build executed for $pkg:$ver"

        local installed_dir="${PKGS_DIR:?}/$pkg/$ver"
        [[ -d "$installed_dir" ]] || installed_dir=$(find "${PKGS_DIR:?}/$pkg" -mindepth 1 -maxdepth 1 -type d | sort | tail -n1)
        if [[ -d "$installed_dir" ]]; then
            ln -sfn "$installed_dir" "${PKGS_DIR:?}/$pkg/HEAD"
            echo -e "$(echo_pkgit) Installed HEAD for $pkg -> $(basename "$installed_dir")"

            if [[ -d "$installed_dir/bin" ]]; then
                mkdir -p "$BIN_DIR"
                for f in "$installed_dir/bin/"*; do
                    [[ -f "$f" && -x "$f" ]] && ln -sf "$f" "$BIN_DIR/$(basename "$f")"
                done
                for f in "$installed_dir/lib/"*; do
                    [[ -f "$f" && -x "$f" ]] && ln -sf "$f" "$LIB_DIR/$(basename "$f")"
                done
                for f in "$installed_dir/include/"*; do
                    [[ -f "$f" && -x "$f" ]] && ln -sf "$f" "$INCLUDE_DIR/$(basename "$f")"
                done
                echo -e "$(echo_pkgit) Symlinked binaries for $pkg -> $BIN_DIR"
            fi
        else
            echo -e "$(echo_pkgit) $(color "$yellow" "[WARNING]") no installed files found for $pkg:$ver"
        fi

        echo -e "$(echo_pkgit) Finished install of $pkg:$ver"
    fi
}

update() {
    echo -e "$(echo_pkgit) $(color "$magenta" "[STATUS]") Updating installed packages..."
    for pkg in "$PKGS_DIR"/*; do
        qpkg=$(basename "$pkg")
        echo -e "$(echo_pkgit) $(color "$blue" "[PACKAGE]") Updating: $qpkg"
        install_pkg "$qpkg"
        echo -e "$(echo_pkgit) $(color "$blue" "[PACKAGE]") Update completed for: $qpkg"
    done
    echo ""
    echo -e "$(echo_pkgit) $(echo_success) All installed packages have been updated."
}

remove_pkg() {
    local input="$1"
    local selected pkg url

    pkg=$(echo "$input" | tr '[:upper:]' '[:lower:]')
    if [[ -z "$pkg" ]]; then
        echo -e "$(echo_pkgit) No package specified"
        return 1
    fi

    selected=$(check_repo_for_pkg "$pkg") || {
        echo "Package selection cancelled or failed."
        return 1
    }

    pkg=$(awk '{print $1}' <<<"$selected" | tr -d '\r\n')
    url=$(awk '{print $2}' <<<"$selected" | tr -d '\r\n')

    [[ -d "${PKGS_DIR:?}/$pkg" ]] || {
        echo -e "$(echo_pkgit) Package $pkg not installed"
        return 1
    }

    if [[ -d "${PKGS_DIR:?}/$pkg/LATEST/bin" ]]; then
        for f in "${PKGS_DIR:?}/$pkg/LATEST/bin/"*; do
            [[ -f "$f" ]] && rm -f "${BIN_DIR:?}/$(basename "$f")"
        done
    fi

    rm -rf "${BIN_DIR:?}/$pkg" "${PKGS_DIR:?}/$pkg" "${BUILD_DIR:?}/$pkg-"*
    echo -e "$(echo_pkgit) Removed $pkg"
}

remove_repo() {
    local repo=$(echo "$1" | tr '[:upper:]' '[:lower:]')
    [[ -z "$repo" ]] && {
        echo -e "$(echo_pkgit) No repo specified"
        return 1
    }
    [[ $(grep "$repo" "$USER_REPOS_DIR"/*) ]] || {
        echo -e "$(echo_pkgit) Repo $repo does not exist"
        return 1
    }

    for file in "$USER_REPOS_DIR"/*; do
        sed -i "/$repo/d" $file
    done
    echo -e "$(echo_pkgit) Removed $repo"
}

list_pkgs() {
    ls "$PKGS_DIR" 2>/dev/null || echo "No packages installed"
}

list_repos() {
    cat "$USER_REPOS_DIR/repos" || echo "No repos exist"
}

search_pkgs() {
    local search_terms="${@:2}"
    echo ""
    for term in $search_terms; do
        echo "results for: $term"
        grep -F "$term" "$USER_REPOS_DIR/repos"
        echo ""
    done
}

pkgit_help() {
    echo -e """$(color "$bold_magenta" "pkgit") - package it!
    $(color "$magenta" "v$VERSION")

    $(color "$red" "options:")
    $(shortopt "h")                   $(or)   $(longopt "help")                         $(desc "# display this help message")
    $(shortopt "ar" "[url.git]")        $(or)   $(longopt "add-repo" "[url.git]")           $(desc "# add a package to your repo")
    $(shortopt "ir" "[url.git]")        $(or)   $(longopt "install-repo " "[url.git]")      $(desc "# add and install a package")
    $(shortopt "arp" "[url || file]")   $(or)   $(longopt "add-repo-pkg" "[url || file]")   $(desc "# add a list of repos")
    $(shortopt "i" "[pkgs]")            $(or)   $(longopt "install" "[pkgs]")               $(desc "# install a package")
    $(shortopt "r" "[pkgs]")            $(or)   $(longopt "remove" "[pkgs]")                $(desc "# remove an installed package")
    $(shortopt "rr" "[repos]")          $(or)   $(longopt "remove-repo" "[repos]")          $(desc "# remove a package repo")
    $(shortopt "lp")                  $(or)   $(longopt "list-pkgs")                    $(desc "# list installed packages")
    $(shortopt "lr")                  $(or)   $(longopt "list-repos")                   $(desc "# list local repos")
    $(shortopt "s" "[pkgs]")            $(or)   $(longopt "search" "[pkgs]")                $(desc "# search for packages")
    $(shortopt "sy")                  $(or)   $(longopt "sync")                         $(desc "# update the repos")
    $(shortopt "up")                  $(or)   $(longopt "update")                       $(desc "# update all installed packages")
    $(shortopt "ug")                  $(or)   $(longopt "upgrade")                      $(desc "# update pkgit")
    """
}

#
# --- logic --- #
#

autogen "$@"

case ${1:-} in
ar | add-repo)
    if ((EUID != 0)); then
        exec "$su" "$0" "$@"
    fi
    repo_from_git $2
    ;;
arp | add-repo-pkg)
    if ((EUID != 0)); then
        exec "$su" "$0" "$@"
    fi
    add_repo_pkg $2
    ;;
ir | install-repo)
    if ((EUID != 0)); then
        exec "$su" "$0" "$@"
    fi
    repo_from_git ${@:2}
    install_pkg $(grep "$2" "$USER_REPOS_DIR/repos" | awk '{print $1}')
    ;;
i | install)
    if ((EUID != 0)); then
        exec "$su" "$0" "$@"
    fi
    install_pkg $2
    ;;
r | remove)
    if ((EUID != 0)); then
        exec "$su" "$0" "$@"
    fi
    remove_pkg $2
    ;;
rr | remove-repo)
    if ((EUID != 0)); then
        exec "$su" "$0" "$@"
    fi
    remove_repo $2
    ;;
lp | list-pkgs)
    list_pkgs
    ;;
lr | list-repos)
    list_repos
    ;;
s | search)
    search_pkgs $@
    ;;
sy | sync)
    if ((EUID != 0)); then
        exec "$su" "$0" "$@"
    fi
    sync $@
    ;;
up | update)
    if ((EUID != 0)); then
        exec "$su" "$0" "$@"
    fi
    update
    ;;
ug | upgrade)
    repo_from_git "https://github.com/dacctal/pkgit"
    install_pkg "pkgit"
    ;;
h | help | *)
    pkgit_help
    ;;
esac
