#!/usr/bin/env bash

# Exit immediately if a pipeline returns a non-zero status (optional, but let's be careful about error handling).
# We won't use 'set -e' globally to handle errors gracefully with custom messages.

# Default settings
RECURSIVE=false
DRY_RUN=false
VERBOSE=false

# Print usage information
show_help() {
    cat << EOF
Usage: $(basename "$0") [options] [file_or_directory ...]

Identify HEIC/HEIF files and rename them to have a '.heic' extension.

Options:
  -r, --recursive   Search directories recursively.
  -d, --dry-run     Show what would be renamed, without renaming anything.
  -v, --verbose     Print verbose output (e.g. files skipped).
  -h, --help        Show this help message.

If no file or directory is specified, the script processes files in the
current directory (non-recursively, unless -r is specified).
EOF
}

# Parse command line options
POSITIONAL_ARGS=()

while [[ $# -gt 0 ]]; do
    case "$1" in
        -r|--recursive)
            RECURSIVE=true
            shift
            ;;
        -d|--dry-run)
            DRY_RUN=true
            shift
            ;;
        -v|--verbose)
            VERBOSE=true
            shift
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        -*)
            echo "Error: Unknown option $1" >&2
            show_help >&2
            exit 1
            ;;
        *)
            POSITIONAL_ARGS+=("$1")
            shift
            ;;
    esac
done

# If no files/directories are specified, default to the current directory "."
if [[ ${#POSITIONAL_ARGS[@]} -eq 0 ]]; then
    POSITIONAL_ARGS+=(".")
fi

# Function to check if a file is an HEIC/HEIF image
is_heic_heif() {
    local filepath="$1"
    
    # 1. Use the 'file' command (mime-type and description checks)
    if command -v file >/dev/null 2>&1; then
        local mime
        mime=$(file -b --mime-type "$filepath" 2>/dev/null | tr '[:upper:]' '[:lower:]')
        if [[ "$mime" =~ image/heic || "$mime" =~ image/heif || "$mime" =~ image/x-heic ]]; then
            return 0
        fi
        
        local desc
        desc=$(file -b "$filepath" 2>/dev/null | tr '[:upper:]' '[:lower:]')
        if [[ "$desc" =~ heif || "$desc" =~ heic || "$desc" =~ "high efficiency image" ]]; then
            return 0
        fi
    fi
    
    # 2. Magic bytes fallback (reads first 48 bytes using od/dd)
    if [[ -r "$filepath" ]]; then
        if command -v od >/dev/null 2>&1; then
            # Read first 48 bytes in hex (excluding spaces/newlines)
            local hex
            hex=$(dd if="$filepath" bs=1 count=48 2>/dev/null | od -An -tx1 | tr -d ' \n\t')
            # 'ftyp' in hex is '66747970' at byte offset 4 (hex chars 8-15)
            if [[ "${hex:8:8}" == "66747970" ]]; then
                # Check for common HEIF/HEIC brand identifiers:
                # 'heic' = 68656963, 'heix' = 68656978, 'hevc' = 68657663, 'hevx' = 68657678
                # 'heif' = 68656966, 'heim' = 6865696d, 'heis' = 68656973
                # 'mif1' = 6d696631, 'msf1' = 6d736631
                if [[ "$hex" =~ "68656963" || "$hex" =~ "68656978" || "$hex" =~ "68657663" || "$hex" =~ "68657678" || \
                      "$hex" =~ "68656966" || "$hex" =~ "6865696d" || "$hex" =~ "68656973" || \
                      "$hex" =~ "6d696631" || "$hex" =~ "6d736631" ]]; then
                    return 0
                fi
            fi
        fi
    fi
    
    return 1
}

# Function to process a single file
process_file() {
    local filepath="$1"
    
    # Only process regular files
    if [[ ! -f "$filepath" ]]; then
        return
    fi
    
    # Extract file name for checking current extension
    local filename
    filename=$(basename "$filepath")
    
    # If the file already ends with .heic (case-insensitive), skip it
    if [[ "$filename" =~ \.[hH][eE][iI][cC]$ ]]; then
        if [[ "$VERBOSE" == "true" ]]; then
            echo "Skipped: '$filepath' already ends with .heic extension."
        fi
        return
    fi
    
    # Check if the file is HEIC/HEIF
    if is_heic_heif "$filepath"; then
        local dir
        dir=$(dirname "$filepath")
        
        local new_filename
        # If it ends with .heif/.HEIF/.heifs/.HEIFS, replace it; otherwise, append .heic
        if [[ "$filename" =~ \.[hH][eE][iI][fF][sS]?$ ]]; then
            new_filename="${filename%.*}.heic"
        else
            new_filename="${filename}.heic"
        fi
        
        local new_filepath="${dir}/${new_filename}"
        
        # Avoid overwriting an existing file
        if [[ -e "$new_filepath" ]]; then
            echo "Warning: Cannot rename '$filepath' to '$new_filepath' - target file already exists." >&2
            return
        fi
        
        if [[ "$DRY_RUN" == "true" ]]; then
            echo "[Dry-Run] Rename: '$filepath' -> '$new_filepath'"
        else
            if mv "$filepath" "$new_filepath"; then
                echo "Renamed: '$filepath' -> '$new_filepath'"
            else
                echo "Error: Failed to rename '$filepath' to '$new_filepath'" >&2
            fi
        fi
    else
        if [[ "$VERBOSE" == "true" ]]; then
            echo "Skipped: '$filepath' is not an HEIC/HEIF file."
        fi
    fi
}

# Main processing loop
for target in "${POSITIONAL_ARGS[@]}"; do
    if [[ -f "$target" ]]; then
        process_file "$target"
    elif [[ -d "$target" ]]; then
        if [[ "$RECURSIVE" == "true" ]]; then
            # Find files recursively and process them
            # Using -print0 and read -d '' to safely handle filenames with spaces or newlines
            find "$target" -type f -print0 | while IFS= read -r -d '' file; do
                process_file "$file"
            done
        else
            # Find files in the directory non-recursively (depth 1)
            find "$target" -maxdepth 1 -type f -print0 | while IFS= read -r -d '' file; do
                process_file "$file"
            done
        fi
    else
        echo "Error: '$target' is not a valid file or directory." >&2
    fi
done
