#!/bin/bash
# Verifies installed packages come from the expected source (pacman/AUR/flatpak).
# Reports missing packages, wrong-source installs, and unexpected foreign packages.
# Pass --fix / -f to automatically reinstall packages from the correct source.
set -euo pipefail

RED="\e[31m"; YELLOW="\e[33m"; GREEN="\e[32m"; CYAN="\e[36m"; BOLD="\e[1m"; RESET="\e[0m"

ok()   { echo -e "  ${GREEN}✔${RESET} $1"; }
warn() { echo -e "  ${YELLOW}⚠${RESET} $1"; }
err()  { echo -e "  ${RED}✘${RESET} $1"; }
hdr()  { echo -e "\n${BOLD}${CYAN}$1${RESET}"; }
fix()  { echo -e "  ${CYAN}↺${RESET} $1"; }

FIX=0
[[ "${1:-}" == "--fix" || "${1:-}" == "-f" ]] && FIX=1

ISSUES=0
flag() { ISSUES=$((ISSUES + 1)); }

WRONG_SOURCE_OFFICIAL=()   # expected from pacman, installed from AUR
WRONG_SOURCE_AUR=()        # expected from AUR, installed from official

# ---------------------------------------------------------------------------
# Expected package sources — keep in sync with setup/modules/
# ---------------------------------------------------------------------------

PACMAN_PKGS=(
    # core-packages.sh
    7zip arch-install-scripts atftp atool
    base base-devel bind bluez btrfs-progs btop
    cockpit cockpit-files cockpit-podman cronie curl
    distrobox fail2ban fastfetch fd ffmpeg firefox flatpak
    gcc glib2 greetd-tuigreet grub
    htop inetutils iwd jq ldns less libpulse linux linux-firmware
    man-db mc nano neovim networkmanager
    openssh pciutils pipewire podman podman-compose
    python python-pip qrencode ruby-pkg-config rust rustup
    ipcalc iputils mtr net-tools nmap
    smartmontools symlinks tcpdump traceroute tree
    udisks2 udisks2-btrfs udiskie ufw usbutils
    vim vnstat wget wireplumber wireless_tools wpa_supplicant wprs
    yazi zip unzip zram-generator
    # shell-setup.sh
    zsh pyright bash atftp bash-language-server clang fzf hyfetch
    lua-language-server micro pulsemixer z dysk glow
    # hyprland.sh (official-repo portion)
    hyprland hyprcursor wl-clipboard hyprpaper hyprlock wofi kitty dunst
    nwg-dock-hyprland nwg-drawer nwg-menu nwg-look
    cmake meson cpio pkgconf
    hyprsunset hypridle ksshaskpass
    nm-connection-editor network-manager-applet blueman
    pipewire alsa-utils greetd-tuigreet
    grim slurp gst-plugin-pipewire imagemagick
    nerd-fonts otf-font-awesome
    pipewire-alsa pipewire-jack pipewire-pulse
    qt5-wayland qt6-wayland swww ttf-jetbrains-mono
    qt6ct xdg-desktop-portal-hyprland xdg-utils
    xorg-server xorg-xinit papirus-icon-theme
    cool-retro-term qalculate-gtk dbus
    thunar tumbler thunar-archive-plugin thunar-shares-plugin thunar-volman
    hyprpicker pcmanfm-qt ly
    hyprpolkitagent pavucontrol playerctl wf-recorder sound-theme-freedesktop
    kew
)

AUR_PKGS=(
    # hyprland.sh AUR portion
    hyprland-workspaces vicinae-bin bluetuith wvkbd iwmenu
    walker-bin ulauncher bzmenu wofi-calc bri chamel
    # optional apps
    pamtester
    pinta
    localsend
    vesktop
    onlyoffice-bin
    vintagestory
    wprs-git
    zfs-dkms
)

FLATPAK_PKGS=(
    org.prismlauncher.PrismLauncher
)

# ---------------------------------------------------------------------------
# Snapshot current state
# ---------------------------------------------------------------------------

ALL_INSTALLED=$(pacman -Qq 2>/dev/null)
FOREIGN=$(pacman -Qmq 2>/dev/null)         # AUR / manually installed
OFFICIAL=$(pacman -Qnq 2>/dev/null)        # in a sync repo

is_installed()      { echo "$ALL_INSTALLED" | grep -qx "$1"; }
is_from_official()  { echo "$OFFICIAL"      | grep -qx "$1"; }
is_from_aur()       { echo "$FOREIGN"       | grep -qx "$1"; }

# ---------------------------------------------------------------------------
# 1. Check pacman packages
# ---------------------------------------------------------------------------

hdr "1/3  Official-repo packages (pacman)"

for pkg in "${PACMAN_PKGS[@]}"; do
    if ! is_installed "$pkg"; then
        err "$pkg — NOT INSTALLED"; flag
    elif is_from_aur "$pkg"; then
        warn "$pkg — installed, but from AUR instead of official repo"; flag
        WRONG_SOURCE_OFFICIAL+=("$pkg")
    else
        ok "$pkg"
    fi
done

# ---------------------------------------------------------------------------
# 2. Check AUR packages
# ---------------------------------------------------------------------------

hdr "2/3  AUR packages (yay)"

for pkg in "${AUR_PKGS[@]}"; do
    if ! is_installed "$pkg"; then
        warn "$pkg — not installed (optional — may be intentional)"
    elif is_from_official "$pkg"; then
        warn "$pkg — installed from official repo, not AUR (may need AUR build for correct version)"; flag
        WRONG_SOURCE_AUR+=("$pkg")
    else
        ok "$pkg"
    fi
done

# ---------------------------------------------------------------------------
# 3. Check flatpak packages
# ---------------------------------------------------------------------------

hdr "3/3  Flatpak packages"

if command -v flatpak &>/dev/null; then
    FLATPAK_INSTALLED=$(flatpak list --app --columns=application 2>/dev/null)
    for pkg in "${FLATPAK_PKGS[@]}"; do
        if echo "$FLATPAK_INSTALLED" | grep -qx "$pkg"; then
            ok "$pkg"
        else
            warn "$pkg — not installed (optional — may be intentional)"
        fi
    done
else
    warn "flatpak not found — skipping flatpak checks"
fi

# ---------------------------------------------------------------------------
# 4. Flag unexpected foreign (AUR) packages not in our lists
# ---------------------------------------------------------------------------

hdr "Bonus: foreign packages not declared in setup scripts"

AUR_SET=$(printf "%s\n" "${AUR_PKGS[@]}")
while IFS= read -r pkg; do
    if ! echo "$AUR_SET" | grep -qx "$pkg"; then
        echo -e "  ${CYAN}?${RESET} $pkg — foreign package not in setup scripts"
    fi
done <<< "$FOREIGN"

# ---------------------------------------------------------------------------
# Fix: reinstall wrong-source packages
# ---------------------------------------------------------------------------

FIXED=0

if [ "$FIX" -eq 1 ]; then
    if [ ${#WRONG_SOURCE_OFFICIAL[@]} -gt 0 ] || [ ${#WRONG_SOURCE_AUR[@]} -gt 0 ]; then
        hdr "Reinstalling wrong-source packages"
    fi

    for pkg in "${WRONG_SOURCE_OFFICIAL[@]}"; do
        fix "Reinstalling $pkg from official repo (was AUR)..."
        if sudo pacman -S --noconfirm "$pkg"; then
            ok "$pkg reinstalled from official repo"
            FIXED=$((FIXED + 1))
            ISSUES=$((ISSUES - 1))
        else
            err "$pkg reinstall failed"
        fi
    done

    for pkg in "${WRONG_SOURCE_AUR[@]}"; do
        fix "Reinstalling $pkg from AUR (was official repo)..."
        if yay -S --aur --noconfirm "$pkg"; then
            ok "$pkg reinstalled from AUR"
            FIXED=$((FIXED + 1))
            ISSUES=$((ISSUES - 1))
        else
            err "$pkg reinstall failed"
        fi
    done
fi

# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------

echo
if [ "$FIX" -eq 1 ] && [ "$FIXED" -gt 0 ]; then
    echo -e "${GREEN}${BOLD}Fixed ${FIXED} wrong-source package(s).${RESET}"
fi

if [ "$ISSUES" -eq 0 ]; then
    echo -e "${GREEN}${BOLD}All checks passed — no source mismatches or missing required packages.${RESET}"
else
    echo -e "${RED}${BOLD}${ISSUES} issue(s) found — review items marked ✘ or ⚠ above.${RESET}"
    [ "$FIX" -eq 0 ] && [ $((${#WRONG_SOURCE_OFFICIAL[@]} + ${#WRONG_SOURCE_AUR[@]})) -gt 0 ] && \
        echo -e "${YELLOW}  Run with --fix to automatically reinstall wrong-source packages.${RESET}"
    exit 1
fi
