#!/usr/bin/env bash
#
# Copyright © 2026 PaperCut Software IP Pty. Ltd.
#
# PaperCut Rosetta Deprecation Audit Tool
# Evaluates active queues, installed PPDs, and latent macOS driver binaries.
# Outputs to a structured CSV file on the Desktop.

set -euo pipefail

# ---------------------------------------------------------
# Environment Setup & Logging
# ---------------------------------------------------------
USER_DESKTOP=$(dscl . -read /Users/"$(whoami)" NFSHomeDirectory | awk '{print $2}')/Desktop
# If run via sudo, fallback to the actual logged-in user's desktop
if [ -n "${SUDO_USER:-}" ]; then
    USER_DESKTOP=$(dscl . -read /Users/"$SUDO_USER" NFSHomeDirectory | awk '{print $2}')/Desktop
fi

CSV_FILE="$USER_DESKTOP/rosetta_print_audit_report.csv"
PPD_DIR="/Library/Printers/PPDs/Contents/Resources"
SYSTEM_FILTER_DIR="/usr/libexec/cups/filter"
SYSTEM_BACKEND_DIR="/usr/libexec/cups/backend"
TARGET_DIR="/Library/Printers"

# Temporary files for tracking
REF_BINARIES=$(mktemp)

# Write CSV Headers
# Added "Technology Context" column to explain plain-English queue types.
echo "\"Audit Category\",\"Item Name\",\"Component Type\",\"Path or URI\",\"Technology Context\",\"Architecture Status\"" > "$CSV_FILE"

# Log OS Context
MAC_VERSION=$(sw_vers -productVersion)
HARDWARE_ARCH=$(uname -m)

echo "======================================================="
echo " PaperCut Print Driver Architecture Audit"
echo " macOS Version: $MAC_VERSION | CPU: $HARDWARE_ARCH"
echo " Report generating at: $CSV_FILE"
echo "======================================================="
echo "Scanning..."

# ---------------------------------------------------------
# Helper Function: Check Architecture
# ---------------------------------------------------------
check_arch() {
    local file_path="$1"
    if [ ! -f "$file_path" ]; then
        echo "MISSING_FILE"
        return
    fi
    
    local file_info
    file_info=$(file -b "$file_path" 2>/dev/null | head -n 1)
    
    if [[ "$file_info" == *"Mach-O"* ]]; then
        if [[ "$file_info" == *"universal"* || ("$file_info" == *"arm64"* && "$file_info" == *"x86_64"*) ]]; then
            echo "UNIVERSAL"
        elif [[ "$file_info" == *"arm64"* ]]; then
            echo "ARM64"
        elif [[ "$file_info" == *"x86_64"* || "$file_info" == *"i386"* ]]; then
            echo "INTEL (ROSETTA DEPENDENT)"
        else
            echo "UNKNOWN BINARY"
        fi
    else
        echo "NOT A BINARY"
    fi
}

# ---------------------------------------------------------
# PHASE 1: Active Print Queues & Backends
# ---------------------------------------------------------
echo " -> Phase 1: Auditing Active Print Queues..."

if [ -d "/etc/cups/ppd" ]; then
    for queue_ppd in /etc/cups/ppd/*.ppd; do
        [ -e "$queue_ppd" ] || continue
        queue_name=$(basename "$queue_ppd" .ppd)
        
        # Get Device URI and Backend
        device_uri=$(lpstat -v "$queue_name" 2>/dev/null | sed -n 's/.*: \(.*\)/\1/p')
        backend_scheme=$(echo "$device_uri" | cut -d':' -f1)
        
        # Check if Driverless/AirPrint and explain it in plain English
        if [[ "$device_uri" == ipp* || "$device_uri" == *dnssd* || "$device_uri" == ipps* ]]; then
            echo "\"Active Queue\",\"$queue_name\",\"Protocol\",\"$device_uri\",\"Driverless / Apple Native (Safe)\",\"N/A\"" >> "$CSV_FILE"
        else
            echo "\"Active Queue\",\"$queue_name\",\"Protocol\",\"$device_uri\",\"Standard Driver-Based (Check binaries below)\",\"N/A\"" >> "$CSV_FILE"
        fi

        # Audit Backend Binary
        if [ -n "$backend_scheme" ]; then
            backend_path="$SYSTEM_BACKEND_DIR/$backend_scheme"
            if [ -f "$backend_path" ]; then
                arch_status=$(check_arch "$backend_path")
                echo "\"Active Queue\",\"$queue_name\",\"CUPS Backend\",\"$backend_path\",\"\",\"$arch_status\"" >> "$CSV_FILE"
                echo "$backend_path" >> "$REF_BINARIES"
            fi
        fi

        # Audit Filters for this active queue
        filter_lines=$(cat "$queue_ppd" 2>/dev/null | grep -iE "^\*cupsFilter(2)?:" || true)
        if [ -n "$filter_lines" ]; then
            echo "$filter_lines" | while read -r line; do
                filter_target=$(echo "$line" | awk -F'"' '{print $2}' | awk '{print $3}')
                [ -z "$filter_target" ] && filter_target=$(echo "$line" | awk '{print $NF}' | tr -d '"\r\n')
                [ -z "$filter_target" ] && continue
                
                # --- BUG FIX: Reject anything that is just numbers, dots, or hyphens ---
                if [[ "$filter_target" =~ ^[0-9.-]+$ ]]; then
                    continue
                fi
                # -----------------------------------------------------------------------
                
                if [[ "$filter_target" == /* ]]; then
                    binary_path="$filter_target"
                else
                    binary_path="$SYSTEM_FILTER_DIR/$filter_target"
                fi
                
                arch_status=$(check_arch "$binary_path")
                echo "\"Active Queue\",\"$queue_name\",\"CUPS Filter\",\"$binary_path\",\"\",\"$arch_status\"" >> "$CSV_FILE"
                echo "$binary_path" >> "$REF_BINARIES"
            done
        fi
    done
fi

# ---------------------------------------------------------
# PHASE 2: All Installed PPDs
# ---------------------------------------------------------
echo " -> Phase 2: Auditing Installed Manufacturer PPDs..."

if [ -d "$PPD_DIR" ]; then
    find "$PPD_DIR" -type f 2>/dev/null | while read -r ppd_path; do
        ppd_name=$(basename "$ppd_path")
        
        if [[ "$ppd_name" == *.gz ]]; then
            filter_lines=$(gzcat "$ppd_path" 2>/dev/null | grep -iE "^\*cupsFilter(2)?:" || true)
        else
            filter_lines=$(cat "$ppd_path" 2>/dev/null | grep -iE "^\*cupsFilter(2)?:" || true)
        fi

        [ -z "$filter_lines" ] && continue

        echo "$filter_lines" | while read -r line; do
            filter_target=$(echo "$line" | awk -F'"' '{print $2}' | awk '{print $3}')
            [ -z "$filter_target" ] && filter_target=$(echo "$line" | awk '{print $NF}' | tr -d '"\r\n')
            [ -z "$filter_target" ] && continue
            
            # --- BUG FIX: Reject anything that is just numbers, dots, or hyphens ---
            if [[ "$filter_target" =~ ^[0-9.-]+$ ]]; then
                continue
            fi
            # -----------------------------------------------------------------------
            
            if [[ "$filter_target" == /* ]]; then
                binary_path="$filter_target"
            else
                binary_path="$SYSTEM_FILTER_DIR/$filter_target"
            fi

            arch_status=$(check_arch "$binary_path")
            echo "\"Installed PPD\",\"$ppd_name\",\"Filter Dependency\",\"$binary_path\",\"\",\"$arch_status\"" >> "$CSV_FILE"
            echo "$binary_path" >> "$REF_BINARIES"
        done
    done
fi

# Remove duplicates from the reference tracking file to speed up Phase 3
sort -u "$REF_BINARIES" -o "$REF_BINARIES"

# ---------------------------------------------------------
# PHASE 3: Latent/Secondary Intel Binaries
# ---------------------------------------------------------
echo " -> Phase 3: Sweeping for Latent Intel Binaries..."

if [ -d "$TARGET_DIR" ]; then
    find "$TARGET_DIR" -type f -print0 2>/dev/null | while IFS= read -r -d '' file_path; do
        
        # Skip if it is already logged from Phase 1 or 2
        if grep -qFx "$file_path" "$REF_BINARIES"; then
            continue
        fi

        file_info=$(file -b "$file_path" 2>/dev/null | head -n 1)
        
        # Only process Mach-O compiled code
        if [[ "$file_info" == *"Mach-O"* && ("$file_info" == *"executable"* || "$file_info" == *"shared library"* || "$file_info" == *"bundle"*) ]]; then
            
            # Identify purely Intel architecture files
            if [[ "$file_info" == *"x86_64"* || "$file_info" == *"i386"* ]]; then
                if [[ "$file_info" != *"universal"* && "$file_info" != *"arm64"* ]]; then
                    vendor_folder=$(echo "$file_path" | awk -F'/' '{print $4}')
                    echo "\"Latent Binary\",\"$vendor_folder Package\",\"Unreferenced Driver Core\",\"$file_path\",\"\",\"INTEL (ROSETTA DEPENDENT)\"" >> "$CSV_FILE"
                fi
            fi
        fi
    done
fi

# Clean up
rm -f "$REF_BINARIES"

echo "======================================================="
echo " Audit Complete. Report saved to:"
echo " $CSV_FILE"
echo "======================================================="