#!/bin/bash

# lib/backup.sh
# Secure Backup Utilities

# Encrypt directory to tar.gz.gpg
backup_encrypt_dir() {
    local source_dir="$1"
    local dest_file="$2"
    
    if [ -z "$source_dir" ]; then
        error "Usage: backup_encrypt_dir <source_dir> [dest_file]"
        return 1
    fi
    # Default filename if not provided
    if [ -z "$dest_file" ]; then
        dest_file="backup-$(date +%F-%H%M).tar.gz.gpg"
    fi
    
    if [ ! -d "$source_dir" ]; then
        error "Source directory not found: $source_dir"
        return 1
    fi
    
    info "Archiving and Encrypting '$source_dir' to '$dest_file'..."
    
    if [ -f "$dest_file" ]; then
        warn "Destination file '$dest_file' already exists."
        if ! ask_confirmation "Overwrite existing backup?"; then
            info "Backup cancelled."
            return 0
        fi
    fi

    info "You will be asked for a passphrase by GPG."
    
    # tar -> gzip -> gpg
    # Using - (stdout) for tar to pipe
    # tar -> gzip -> gpg
    # Using - (stdout) for tar to pipe
    tar zcf - "$source_dir" | gpg -c > "$dest_file"
    local statuses=(${PIPESTATUS[@]})
    
    # Check tar status (index 0)
    if [ ${statuses[0]} -ne 0 ]; then
        error "Archiving failed (tar exit code: ${statuses[0]})."
        rm -f "$dest_file"
        return 1
    fi
    
    # Check gpg status (index 1)
    if [ ${statuses[1]} -ne 0 ]; then
        error "Encryption failed (gpg exit code: ${statuses[1]})."
        rm -f "$dest_file"
        return 1
    fi
    
    success "Backup created at $dest_file"
    return 0
}

# Decrypt backup
backup_decrypt_dir() {
    local source_file="$1"
    local dest_path="$2"
    
    if [ -z "$source_file" ]; then
        error "Usage: backup_decrypt_dir <source_file> [dest_path]"
        return 1
    fi
    
    if [ ! -f "$source_file" ]; then
        error "File not found: $source_file"
        return 1
    fi
    
    # Default filename if not provided
    if [ -z "$dest_path" ]; then
        dest_path="decrypted-$(date +%s).tar.gz"
    fi
    
    info "Decrypting '$source_file'..."
    gpg -o "$dest_path" -d "$source_file"
    
    if [ $? -eq 0 ]; then
        info "Decrypted to $dest_path"
        if ask_confirmation "Extract now?"; then
             tar zxvf "$dest_path"
             success "Extracted."
        fi
    else
        error "Decryption failed."
        return 1
    fi
}

# Create encrypted volume (DMG)
backup_create_volume() {
    local vol_name="$1"
    local vol_size="$2"
    
    if [ -z "$vol_name" ]; then 
        error "Usage: backup_create_volume <vol_name> <vol_size>"
        return 1
    fi
    
    if [ -z "$vol_size" ]; then
        error "Usage: backup_create_volume <vol_name> <vol_size>"
        return 1
    fi
    
    local dmg_name="${vol_name}.dmg"
    
    info "Creating Encrypted DMG ($vol_size)..."
    
    if [ -f "$dmg_name" ]; then
        warn "Volume file '$dmg_name' already exists."
        if ! ask_confirmation "Overwrite existing volume?"; then
            info "Volume creation cancelled."
            return 0
        fi
    fi

    # AES-256 encryption. -stdinpass is hard to script securely in bash without leakage,
    # so we let hdiutil prompt interactively.
    hdiutil create "$dmg_name" -encryption -size "$vol_size" -volname "$vol_name" -fs APFS
    
    if [ $? -eq 0 ]; then
        success "Created $dmg_name"
        info "To mount: hdiutil mount $dmg_name"
    else
        error "Failed to create volume."
        return 1
    fi
}

# Audit Time Machine
backup_audit_timemachine() {
    info "Auditing Time Machine configuration..."
    if ! type tmutil >/dev/null 2>&1; then
        warn "Time Machine util (tmutil) not found."
        return 1
    fi
    
    
    # Check if a backup is currently running
    local is_running=0
    # Use plutil to parse -plist output cleanly
    if status_plist=$(tmutil status -plist 2>/dev/null); then
        # Extract raw value of Running key (true/false)
        local run_val
        if run_val=$(echo "$status_plist" | plutil -extract Running raw -o - - 2>/dev/null); then
            if [[ "$run_val" == "true" || "$run_val" == "1" ]]; then
                is_running=1
            fi
        else
            # Fallback to text parsing if key missing or plutil fails
             if echo "$status_plist" | grep -q "<key>Running</key>.*<true/>"; then
                is_running=1
             fi
        fi
    else
        # Fallback to text parsing "Running = 1;"
        if tmutil status | grep -q "Running = 1"; then
            is_running=1
        fi
    fi
    
    if [ "$is_running" -eq 1 ]; then
        info "Time Machine backup is CURRENTLY RUNNING."
    else
        info "Time Machine is idle."
    fi
    
    info "Destinations:"
    
    # Capture plist output
    local dest_plist
    dest_plist=$(tmutil destinationinfo -plist 2>/dev/null)
    
    if [ -z "$dest_plist" ]; then
        warn "No Time Machine destinations found (or tmutil failed)."
        return 0
    fi

    # Parse MountPoints using robust JSON conversion + Python
    # We convert the plist to JSON and extract the array of MountPoints
    local mount_points=""
    
    if command -v python3 >/dev/null; then
         # Python 3 is available, use it for safe parsing
         mount_points=$(echo "$dest_plist" | plutil -convert json -r -o - - | python3 -c "import sys, json; print('\n'.join([d.get('MountPoint','') for d in json.load(sys.stdin).get('Destinations',[])]))" 2>/dev/null)
    fi
    
    # Fallback to legacy parsing if python failed or is missing, but ensure we don't duplicate
    if [ -z "$mount_points" ]; then
        # Check if we have destinations at least
        if echo "$dest_plist" | grep -q "<key>Destinations</key>"; then
            # Legacy regex parsing (fragile but better than nothing)
            mount_points=$(echo "$dest_plist" | grep -A 1 "<key>MountPoint</key>" | grep "<string>" | sed -E 's/.*<string>(.*)<\/string>.*/\1/')
        fi
    fi
    
    if [ -z "$mount_points" ]; then
        warn "No mounted destinations found."
        echo "$dest_plist" | grep -A 1 "<key>Name</key>" | grep "<string>" | sed -E 's/.*<string>(.*)<\/string>.*/\t- Name: \1 (Not Mounted)/'
        return 0
    fi
    
    while read -r mp; do
        if [ -z "$mp" ]; then continue; fi
        
        local encrypted="UNKNOWN"
        local fs_name=""
        
        # Check diskutil info
        if type diskutil >/dev/null 2>&1; then
            local disk_info
            disk_info=$(diskutil info "$mp" 2>/dev/null)
            
            # Check FileVault or APFS Encryption
            if echo "$disk_info" | grep -q "FileVault:.*Yes" || \
               echo "$disk_info" | grep -q "Encrypted:.*Yes"; then
                encrypted="YES"
            elif echo "$disk_info" | grep -q "FileVault:.*No" || \
                 echo "$disk_info" | grep -q "Encrypted:.*No"; then
                encrypted="NO"
            fi
            
            fs_name=$(echo "$disk_info" | grep "Volume Name:" | awk -F': *' '{print $2}')
        fi
        
        info "- Destination: $mp"
        if [ -n "$fs_name" ]; then
             echo "     Name      : $fs_name"
        fi
        
        if [ "$encrypted" == "YES" ]; then
            success "     Encryption: [ON] (Secure)"
        elif [ "$encrypted" == "NO" ]; then
            error "     Encryption: [OFF] (INSECURE! Enable in Disk Utility)"
        else
            warn "     Encryption: [UNKNOWN] (Could not verify)"
        fi
        
    done <<< "$mount_points"
}
